Filling the Space in the Last Row with Flexbox

Avatar of Chris Coyier
Chris Coyier on

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.