A CSS Grid Based Layout


Since the cool boys and girls are talking a lot about the new CSS Grid specification lately, it’s time to dig into this subject myself. For me, the best way by learning this, is: 1. choose a real world problem and 2. write about it in a post. The first is done and the second are you reading right now.


Please note, this is not a complete guide to CSS Grid. Others have already written about it. I’ve included references after this post. Please, also check the browser support of CSS Grid. At the moment of writing this post (July 2017), the global browser support is around 70%.

This post covers how to create a web layout with CSS Grid. I’ll explain each step and include all HTML and CSS code needed.

Grid layout

I started with a sketch (left). It shows the layout I want to build using the Grid Layout. At the right you see a screenshot of the final result (desktop view).

Original sketch (left) and a screenshot of the final layout created with CSS Grid.

The layout consists of five parts: four text items and a hero (combination of a background image with text). Also, I want layout changes depending on the size of the screen:

  • small screen size: single column with the hero as the second item
  • medium screen size: two column layout with the hero on the second row
  • large screen size: three column layout with hero on last position

This layout can be created quite easily with CSS Grid. I’ve broken the process into six steps. I’ve made Pens of each step, so you can check (and try) the example yourself.

Step 1: the basics of grid

The first thing is setting up the HTML content. I have a grid container (.grid) with five elements (.items). The basic CSS Grid properties are applied to the container:

.grid { 
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 16em 16em;
grid-gap: 1em; padding: 1em;
}

Let me explain the CSS step by step:

With display: grid; you tell the container that, well, the content will be displayed as a grid.

grid-template-columns: 1fr 1fr 1fr;

Now, this is the real stuff. This property defines the grid columns. There are multiple ways of doing this. I found this one the most straight forward.

You see three values, which means I’ve specified the grid has three columns. The width of each column is 1fr. fr is an abbreviation of fraction (part). Because each values is equal (1fr), the width of the columns are equal. The total width of the grid is 3 * 1fr. You can also use values in px, em and %. But fr is specially designed for using with grid, so I highly recommend using this.

grid-template-rows: 16em 16em;

This property is all about the grid rows. The two values means that I’ve specified the height of two columns. Here, I’ve choosen for em, but you can use px as well.

grid-gap: 1em;

This adds a gap between the rows and columns. Please note, it will not add space on the outside of grid. That’s why I included padding: 1em; to the grid container. This gives padding to outside of the grid.

This first step results in the following layout. Which is already quite awesome.


Step 1, a basic grid

Step 2: adaptive for different screen sizes

Because we have used the fr unit, the grid is already responsive. But on small screens the columns get squeezed, making it difficult to read the text. In this step we add the following:

  • on small screens: display the grid in a single column
  • on medium screens: display the grid in two columns
  • on large screens: display the grid in three columns

This can be achieved with CSS Grid and some good old media queries.

Small screens: grid with single column

The only thing we need to do, is deleting the properties grid-template-columns and grid-template-rows. Don’t worry, we wel add them later for medium sized screens. The code for our grid container should be looking like this:

.grid { 
display: grid;
grid-gap: 1em;
}

Medium screens: grid with two columns

We use a media query to target the medium size screens. Inside this media query we add the properties for the grid columns and rows.

.grid { 
display: grid;
grid-gap: 1em;
padding: 1em;
@media screen and (min-width: 24em) {
grid-template-columns: 1fr 1fr;
grid-template-rows: 16em 16em 16em;
}

Please note, I’m using the SASS notation here. This makes it possible to nest the media query inside .grid.

The breakpoint value of 24em is arbitrary and for this example not really important. The goal is to change the grid layout for different screen sizes. And that’s what this code is doing.

As you can see grid-template-columns lists two values. This means, the grid will be shown with two columns. By using the same fraction value, the width of the columns is equal. Because we have five grid items (or cells), we now have three rows. That’s why you can see three values for the grid-template-rows property.

Large screens: grid with three columns

We add the second media query to target large screens:

.grid { 
display: grid;
grid-gap: 1em; padding: 1em;
// create a grid with two columns and three rows
@media screen and (min-width: 24em) {
grid-template-columns: 1fr 1fr;
grid-template-rows: 16em 16em 16em;
}
// change the grid to three columns and two rows
@media screen and (min-width: 48em) {
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 16em 16em;
}
}

We see the values as used originally for grid-template-columns and grid-template-rows. And again, the breakpoint value 48em is arbitrary.

The result is exactly what we wanted. Grid with a single column for small screens, two columns for medium and three columns for large screens.


Step 2, adaptive for different screen sizes

You may have to resize your browser window to see the different layouts.

Step 3: Column span

The next improvement is spanning the image grid cell across two columns. And guess what, this can be done with grid also.

We need the following code:

// for the cell which holds the image 
#hero {
grid-column-start: 2;
grid-column-end: span 2;
// some styles for the background image
}

This can be read as:

  • grid-column-start: 2;: the cell starts at the second column,
  • grid-column-end: span 2;: the cell spans two columns

That’s it.

This results in:


Step 3, column span

Time for another special thing you can easily do with grid.

Step 4: change order of cells for small screens

For small screens I like to have the image visually higher on the page. With grid I’ll change the order of the cells. The image will be on the second row. For this we’ll use ‘order’ property.

// first, set all cells last in order
.item {
@media screen and (max-width: 24em) { order:3; }
}
// secondly, set the first cell back to first in order
.item:nth-child(1) {
@media screen and (max-width: 24em) { order:1; }
}
// set this item second in order
#hero {
@media screen and (max-width: 24em) { order:2; }
}

I’m using max-width for the media query to target small screens only.

With order you can set the visual order of the grid cells. The grid cell with the image is last in the document. With order I’ve set it to second.


Step 4, change order of cells for small screens

Step 5: change order of cells for medium size screens

For medium size screens the grid is displayed in two columns. The image will be on the second row. So instead of one cell, we need two cells on the first row.

I’ll add some changes to the code of the previous step:

// set all cells last in order for small AND medium screens
.item {
@media screen and (max-width: 48em) { order: 3; }
}
// set the first cell back to first in order, for small AND medium screens
.item:nth-child(1) {
@media screen and (max-width: 48em) { order: 1; }
}
// for medium screens ONLY, we want the second cell to have order 1 also
.item:nth-child(2) {
@media screen and (min-width: 24em) and (max-width: 48em) { order:1; }
}

This results in:


Step 5, change order of cells for medium size screens

Step 6, final

We now have a layout that:

  • is build using CSS Grid
  • is shown on small screens in a single column
  • is shown on medium screens in two columns
  • has the image shown higher on the page for small and medium screens

Great! And with CSS grid you don’t need a lot of code.

For the final step I’ve added some color and typographic adjustments. This has nothing to do with the Grid specification, just to make the layout somewhat prettier.

Final result of the layout with CSS Grid on CodePen:


Step 6, final result

Pens

For each step I’ve made a pen on codepen.io:

Step 1: a basic grid
Step 2: adaptive for different screen sizes
Step 3: column span
Step 4: change order of cells for small screens
Step 5: change order of cells for medium size screens
 Step 6: final result

Further reading and references

There are already great things written about CSS Grid. I used the following resources for this post and can highly recommend them.


Originally published at woutervanderzee.nl.