Fixing Flexbox’s Last Row with SASS

Flexbox is great, but it’s not really supposed to be used for grids. Unfortunately, we don’t have the grid layout yet, and sometimes you just really need to use Flex. Or sometimes you just really *want* to — we won’t judge. Here's a small trick to make a Flexbox behave like a grid.

If you’ve been using Flexbox long enough, you’ll have seen something like this, where the last row of items is distributed oddly when using justify-content: space-between:

space-between weirdness

There are plenty of fixes that involve resizing the last item(s), but if you’re working with non-negotiable fixed-width items, you’re going to need something else. Here’s what I’ve come up with.

Quantity Queries

First of all, none of this would be possible without the amazing CSS Quantity Queries work we first learned about from A List Apart. For this fix, we're using the SASS Quantity Query Mixin from Daniel Guillan.

A quick note: this fix will only work if you know the exact width of your items. In this case, here’s what the items looked like:

.item {
  width: calc(33.3334% - 1rem);
  min-height: 275px;
}

Fixing the Problem

Our grid is three items wide, which means that we're going to have trouble any time there are two items on a line. When that happens, we need to move the last item to the left by the width of an item and the bit of space between them. In this case, that’s 33.3334% + .5rem. That’s easily enough accomplished by the following:

position: relative:
right: calc(33.3334% + .5rem);

Now we need to target this rule for only those items that break the formatting (2nd, 5th, 8th, etc.) Unfortunately, we couldn’t find a clean CSS rule for this, though it very well may exist.

This is where quantity queries come in! We can use the mixin to target exactly the 2nd, 5th, 8th, etc. items. We’d do it something like this:

.item {
  width: calc(33.3334% - 1rem);
  min-height: 275px;  
  @include exactly(2) {
    &:last-child {   
      position: relative:
      right: calc(33.3334% + .5rem);
    }  
  }
}

Avoiding the Drudgery

And then include a rule for 5, 8, and so on. We’re going to get around the drudgery of that approach using a SASS @for function. In my case, I’m sure that I won’t ever have more than twelve rows.

.item {
  width: calc(33.3334% - 1rem);
  min-height: 275px;
  @for $i from 0 through 10 {
    // Get 2, 5, 8, etc.
    $exact_number: 2 + ($i * 3);
    @include exactly($exact_number) {
      &:last-child {   
        position: relative:
        right: calc(33.3334% + .5rem);
      }  
    }
  }
}

It’s not pretty, but it works!

It works!