Profile photo of Travis Horn Travis Horn

Some ways to align the last row in a flexbox grid

2021-03-18
Some ways to align the last row in a flexbox grid

Using flexbox doesn’t always produce the expected alignment, especially on the last row of a grid. When you use justify-content: space-between it will place a large gap in the last row unless there are a square number of items.

Say we have a collection of items.

<div class="container">
  <div class="item">One</div>
  <div class="item">Two</div>
  <div class="item">Three</div>
  <div class="item">Four</div>
  <div class="item">Five</div>
</div>

Each item has a fixed height and width.

.item {
  width: 100px;
  height: 100px;
  border: solid;
}

Five white rectangles with black outlines. Each is labeled "One", "Two", etc.
They are stacked vertically upon each other with no
spacing.

If you want to arrange them in a grid, you could use flexbox.

.container {
  width: 450px;
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}

Five white rectangles with black outlines. Each is labeled "One", "Two", etc.
They are arranged in a 3 by 2 grid, with the last space empty. There is some
padding between them.

This actually gives us the effect we are trying to achieve. But each row is too left-aligned. This becomes apparent when you can visualize the container.

.container {
  /* ... snip ... */
  border: solid red;
}

A red rectangle surrounds the set of rectangles. There is no padding on the
left but there is significant padding on the right, but not enough for there to
be room for another black-outlined rectangle.

Many times, you will want to avoid that big gap on the right and justify each row so the items appear with even space between.

.container {
  /* ... snip ... */
  justify-content: space-between;
}

The padding on the right has been eliminated. The rectangles are evenly spaced
to take up the entire width. The bottom two rectangles are stuck to the left and
right side respectively. There is an empty space in the bottom middle with no
rectangle.

Now we have a new issue. There is space between each item in the row just like we defined, but it doesn’t exactly look like what we might expect. It’s a common design pattern to have the last row aligned to the left when there aren’t enough items to fill it.

This is exactly the question on this Stack Overflow question and its many duplicates.

The accepted answer uses ::after.

.container::after {
  content: "";
  flex: auto;
}

But this doesn’t look good at all when you’re using fixed widths like we are here.

The empty space in the middle is gone. The last rectangle is shifted to the
left, but too far to the left so the padding between it and the one to the
left of it is not equal to the rectangles on the first
row.

Adding items to make the grid square

Instead of adding the ::after block above, we can take another approach.

Add another item (or items) so that the grid is square. Give these items a specific class. See the last item below.

<div class="container">
  <div class="item">One</div>
  <div class="item">Two</div>
  <div class="item">Three</div>
  <div class="item">Four</div>
  <div class="item">Five</div>
  <div class="item item-empty"></div>
</div>

A new empty rectangle has been added to the end of the grid. Everything is
aligned well, but there is one rectangle without a
label.

We can hide the item, too.

.item-empty {
  visibility: hidden;
}

The empty rectange is gone. The result looks good.

This technique works well when you know how many items there are or you can calculate it and add items dynamically.

Use CSS grid

One of my favorite approaches is to replace flexbox with grid.

Delete the empty items so we’re left with the original set.

<div class="container">
  <div class="item">One</div>
  <div class="item">Two</div>
  <div class="item">Three</div>
  <div class="item">Four</div>
  <div class="item">Five</div>
</div>

Delete the flexbox CSS on .container. That means delete all of the following:

display: flex;
flex-wrap: wrap;
gap: 20px;
justify-content: space-between;

And add the following grid CSS.

.container {
  /* ... snip ... */
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
  justify-content: space-between;
  grid-gap: 20px;
}

The grid is well aligned, except the last rectangle sticks out to the right
too far.

Since we are defining our columns as 100px wide here, we can remove the following line from .item

width: 100px;

That leaves us with a nicely aligned grid with the last row left-aligned.

A perfectly aligned 3 x 2 grid of five rectangles. The last spot is
empty.

The code and live example for this post can be found on CodePen.

Here are some more articles you might like: