Flexible Grids

Perhaps the greatest trick in all of CSS grid is being able to write a column layout that doesn’t explicitly declare the number of rows or columns, but automatically creates them based on somewhat loose instructions and the content you provide.

CSS Grid has a learning curve, like anything else, but after a minute there is a certain clarity to it. You set up a grid (literally columns and rows), and then place things on those rows. The mental model of it, I’d argue, is simpler than flexbox by a smidge.

Here I’ll set up a grid:

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 1rem;
}

And now if I had three children to put onto that grid…

<div class="grid">
   <div></div>
   <div></div>
   <div></div>
</div>

They would fall onto that grid perfectly. That’s wonderfully easy, and offers us a ton of control. That 1fr unit can be adjusted as needed. If the first one was 2fr instead, it would take up twice as much room as the other two. If it was 200px, it would exactly that wide. The gap can be widened and narrowed. There are all kinds of tools for alignment and explicit placement and ordering.

Let’s think about something else though for a moment. Say there were only 2 children. Well, they would automatically land in the 1st and 2nd columns, if we weren’t otherwise explicit about where we wanted them to go. Say there were 5 children. Well, the 4th and 5th would move down onto a new row automatically. Yes, rows! Our grid so far has totally ignored rows, they are just implied. There is something intuitive about that. You don’t have to care about rows, they can be automatically created. You can be explicit about them, but you don’t have to be.

Here’s the CSS trick: we can extend that “don’t have to care” fun to columns in addition to rows.

One way to do that is by…

  1. Not setting any grid-template-columns
  2. Change the auto-flow away from the default rows to grid-auto-flow: column;

Now there will be as many columns as there are child elements! Plus you can still use gap, which is nice.

But what we’ve lost here is wrapping. It would be nice if the number of columns were based on how many elements could fit without breaking the width of the parent, then doing that for the rest of the grid.

That leads us to perhaps the most famous and useful code in all of CSS grid:

.grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

There is also an auto-fill keyword and they are a bit different, as Sara Soueidan explains.

If you resize this example, you’ll see how the number of columns adjusts:

Also note that the minimum value used here is 200px for each column. That’s just some number that you’d pick that feels good for your content. If that number was, say, 400px instead, you might consider an alteration that allows it to go smaller if the screen itself is smaller than that wide. I first saw this trick from Evan Minto:

grid-template-columns: repeat(auto-fill, minmax(min(10rem, 100%), 1fr));

That’s saying that if 100% width calculates to less than 10rem (otherwise the minimum), then use that instead, making it safer for small-screen layouts.