Chris Albrecht posted a question on StackOverflow about grids. Essentially: imagine you have an element with an unknown number of children. Each of those children is some percentage of the width of parent such that they make equal rows, like 25% wide each for four columns, 33.33% wide each for three columns, etc. The goal is to fill the space of this “grid” evenly. There are an unknown number of children, so let’s say you were going with 25% and there were 7 children, that would be 4 in the first row and 3 in the second. Chris needed the final 3 to adjust in width to fill the space, rather than leaving the gap.
Flexbox has just the answer for this, which would otherwise likely need to be a JavaScript intervention.
The solution is essentially making the children able to wrap with flex-wrap
, and then filling the space with flex-grow
.
.grid {
display: flex;
flex-wrap: wrap;
}
.grid-item {
flex-grow: 1;
min-width: 25%;
}
Here’s a visual example of that when each grid item is red and separated with a border:
By adjusting the min-width at different @media query breakpoints, you can make it responsive pretty easily:
.grid-item {
flex-grow: 1;
min-width: 25%;
}
@media (max-width: 1200px) {
.grid-item {
min-width: 33.33%;
}
}
Here’s that demo:
See the Pen Wrapping Flexbox with Media Query Widths by Chris Coyier (@chriscoyier) on CodePen.
If you like to balk at flexbox for not being ready to use yet, this example is for you. flex-wrap
wasn’t in Firefox at all until pretty recently, and isn’t even in stable yet, so probably not a super practical solution for Chris just yet. But remember Firefox auto-updates so when 28 rolls out everyone will have it pretty quickly. I’m still optimistic flexbox will be a pretty standard layout mechanism on new sites within a year or so.
If you only need flexbox for single-directional stuff, falling back to display: table
is sometimes an option, if by fallback you mean to replicate the layout with some accuracy. If you need the wrapping, inline-block might work. You can test for flexbox wrapping support with:
@supports not (flex-wrap: wrap) {
}
And possibly fall back to inline-block
(with no space between them) If you did that, here’s how you might adjust that last row if needed with JavaScript:
var leftovers = $(".child").removeAttr("style").length % 4;
if (leftovers > 0) {
var newWidth = 100 / leftovers;
var fromHere = $(".child").length - leftovers + 1;
$(".child:nth-child(n+" + fromHere + ")").css("width", newWidth + "%");
}
Note the hard-coded 4 in there, which assumes 25% children. You could get fancier and detect that. I’ll leave that to you. Selecting the last few stragglers (determined by that modulus (%) operator) I did with a bit of an :nth-child recipe. Here’s a demo of it though:
See the Pen Wrapping Flexbox with Media Query Widths by Chris Coyier (@chriscoyier) on CodePen.
Remember there is a big ol’ guide to all the flexbox properties here.
Bookmarks to save the day on every post-IE8 project ever *
IE9 doesn’t have support according to caniuse: http://caniuse.com/#search=flex
Not too hard with some nth-child funkyness, but it’s great to have the flexibility with so few lines of code.
u smart
This really deserves to be added to the article!
Impressive!
clever
Genius
Oooooooh… Is there anything flexbox can’t do?
Firefox 28 should be released March 18 https://wiki.mozilla.org/RapidRelease/Calendar
nice! i was recently looking for something similar – a solution for a balanced flex-wrap navigation with flex auto. the difference to the example above: the width of the containers is not fixed.
Oddly, this doesn’t seem to work in Safari 7.0.2, which is annoying.
CM
To amplify my slightly terse comment, it seems that Safari simply renders the min-width incorrectly—it just keeps on expanding the parent.
If you set the min-width to width, then the parent does not expand—the boxes are rendered on one line and just get smaller and smaller.
I can only get it to work correctly by setting the min-width:25%; to width:25%; and setting all attributes in flex, e.g. flex:1 0 auto;
CM
Flexbox is awesome. I’ve used it in my own grid solution and it’s so useful.
http://grumpywizards.com/Grid/
Help would be appreciated if anyone wanted to contribute to the open source project! ;-)
This doesn’t solve my problem.
What I need is a way to have justify-content: space-between on every flex wrapped line except the last line.
I need the last line to be some kind of combination of space-between & flex-start.
There are also the intrinsic and extrinsic value properties that will hopefully one day help out with this.
http://caniuse.com/#feat=intrinsic-width
http://demosthenes.info/blog/662/Design-From-the-Inside-Out-With-CSS-MinContent
Yeah, late to the party. Whatevs.
Flexbox has the equivalent of “min-width” built into it. Using the shorthand flex property, you could do that all in one declaration:
Meaning: allow it to grow, don’t allow it to shrink, make the width at least 25%
It behaves exactly the same way. The new boxes added below will stretch across to fill the space.