A CSS Grid Based Layout

, by Wouter van der Zee

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).

Sketch and screenshot final result layout created with CSS Grid.
Sketch (left) and screenshot 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). I want to create this layout using Grid.

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

Below is the final result (CodePen embedd):

See the Pen Grid layout 1 – step 6, final by Wouter van der Zee (@woutervanderzee) on CodePen.

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.

See the Pen Grid layout 1 – step 1, a basic grid by Wouter van der Zee (@woutervanderzee) on CodePen.

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.

See the Pen Grid layout 1 – step 2, adaptive for different screen sizes by Wouter van der Zee (@woutervanderzee) on CodePen.

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:

See the Pen Grid layout 1 – step 3, column span by Wouter van der Zee (@woutervanderzee) on CodePen.

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.

This results in:

See the Pen Grid layout 1 – step 4, change order of cells for small screens by Wouter van der Zee (@woutervanderzee) on CodePen.

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:

See the Pen Grid layout 1 – step 5, change order of cells for medium size screens by Wouter van der Zee (@woutervanderzee) on CodePen.

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:

See the Pen Grid layout 1 – step 6, final by Wouter van der Zee (@woutervanderzee) on CodePen.

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.