Christian Johansen

CSS Grid

På Norsk.

CSS grids have finally given us a simple and flexible model for web layout. With just a few properties, you can pretty much retire float, gain full control over source order, and get a powerful tool for responsive design in the bargain.

Published July 3 2019

CSS grids were finalized in December 2017 and now have broad enough browser support to be used practically anywhere. Grids are easy to work with and give you such fine control that the order and placement in your HTML is completely separated from the visual result. This makes it an ideal tool for responsive designs. In this post, I’ll show a couple of fundamental properties that nicely demonstrate the possibilities of CSS grids.

Columns

To create a grid, all you need is a container element with display: grid and an optional specification of the number and size of the columns and/or rows. The child elements of the container will then place themselves into the grid in the order they appear in the source (more on bending that rule later). Here’s a grid with two columns — one that’s 200 pixels wide, and the other taking up the remaining available space:

.grid-container {
  display: grid;
  grid-template-columns: 200px auto;
}
<div class="grid-container">
  <div class="child1"><p>Dette er element #1</p></div>
  <div class="child2"><p>Dette er element #2</p></div>
  <div class="child3"><p>Dette er element #3</p></div>
  <div class="child4"><p>Dette er element #4</p></div>
  <div class="child5"><p>Dette er element #5</p></div>
  <div class="child6"><p>Dette er element #6</p></div>
</div>

This is element #1

This is element #2

This is element #3

This is element #4

This is element #5

This is element #6

Rows

You can similarly define the height of rows using grid-template-rows. If you have more elements than the number of rows specified by grid-template-rows, the additional rows will behave as if they were defined with auto.

.grid-container {
  display: grid;
  grid-template-columns: 25% auto;
  grid-template-rows: auto 200px;
}

This is element #1

This is element #2

This is element #3

This is element #4

This is element #5

This is element #6

Tables go home

If you spice up this setup with grid-gap, grid-column, and grid-row, you’ll have a solution as solid as the good old HTML tables (these correspond to cellpadding, colspan, and rowspan, respectively). You can even control alignment in both directions:

.grid-container3 {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: 25% auto 25%;
  grid-template-rows: auto 200px;
}

.child1 {
  grid-column: 1 / 3;
}

.child2 {
  grid-column: 3;
  grid-row: 1 / 4;
}

This is element #1

This is element #2

This is element #3

This is element #4

This is element #5

This is element #6

The middle column above gets auto width, not 50%. This way, there’s room for grid gaps without the grid becoming wider than the available space (25% + 10px + 50% + 10px + 25%).

Grid units

So far, we’ve defined row and column dimensions using percentages, pixels, and auto. But the absolute coolest unit is the relative grid unit fr. The full width of the grid is the sum of all fr units you’ve assigned to the columns, and a single column will take up the portion of space that its fr value represents relative to the total.

In short: with three columns set to 1fr, each column will take up one third of the space:

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

This is element #1

This is element #2

This is element #3

This is element #4

This is element #5

This is element #6

To create a grid with 2 + 1 + 3, you can simply distribute more fr units:

.grid-container5 {
  display: grid;
  grid-template-columns: 2fr 1fr 3fr;
}

This is element #1

This is element #2

This is element #3

This is element #4

This is element #5

This is element #6

Full flex

So far, we’ve seen how grids easily and elegantly solve some notoriously tricky problems in CSS. But the best is yet to come: grid-template-areas. This is the icing on the cake that lets you completely separate structural representation (the HTML elements) from visual representation. It works by giving the container element an ASCII-art representation of which elements should go where in the grid, and then you name each of the child elements. Voila — your elements get placed exactly where you want them.

.grid-container6 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-areas: "child5 child1 child4"
                       "child2 child6 child3"
}

.child1 { grid-area: child1; }
.child2 { grid-area: child2; }
.child3 { grid-area: child3; }
.child4 { grid-area: child4; }
.child5 { grid-area: child5; }
.child6 { grid-area: child6; }

This is element #1

This is element #2

This is element #3

This is element #4

This is element #5

This is element #6

As if that wasn’t cool enough on its own, you can also use this to visually and neatly make elements span multiple rows and/or columns:

.grid-container7 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr 1fr;
  grid-template-areas: "child5 child1 child1"
                       "child5 child2 child2"
                       "child4 child2 child2"
                       "child3 child3 child6";
}

This is element #1

This is element #2

This is element #3

This is element #4

This is element #5

This is element #6

Note! This example creates a layout with two columns (see below) on mobile and screens under 800px, and three columns on larger screens.

For clarity, I should mention that there are also other ways to achieve colspan and rowspan in CSS grids that don’t rely on grid-template-areas.

I mentioned earlier that CSS grids provide an ideal solution for responsive layouts, and as an example, you can look at the grid above by resizing your browser window to less than 800px (or wider than 800px, depending). You can completely change the layout with a simple media query:

@media screen and (max-width: 800px) {
  .grid-container7 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "child3 child4"
                         "child3 child1"
                         "child2 child1"
                         "child6 child5";
  }
}

It’s worth mentioning that grid-template-areas is a highly programmable layout mechanism and can easily be used to programmatically control the layout in your apps. Examples of this will follow in a later blog post.

What about Internet Explorer?

It is not without a certain amount of frustration that it’s 2019 and we still have to ask this question. We live in difficult times. A time when there are still people using IE11 on the internet. IE11 (and Edge up to version 15) implements an early draft of CSS grids, and with this you can make some things work (Mozilla also has some tips).

Of the things I’ve shown here, for example, grid-template-areas is not possible in these browsers.

I’ve stopped dealing with this problem by simply dropping display: -ms-grid. IE then just shows a bunch of block elements stacked vertically. It’s still functional, but takes up more space and has no elements side-by-side. Given the low share of users still using these outdated browsers, my project is perfectly fine with this solution. Others are advised to check their own browser statistics before deciding if this works for their projects.

Learn more

If you’re as enthusiastic as I am, you’ll probably want to learn more about grids — there are lots of details I haven’t covered here. I highly recommend css-tricks.com’s visual guide — it covers most of it with visual examples. I regularly use it as a reference.