CSS Grid: Layouts Made Easy

CSS3 has given us all the ability to create sharp, professional-looking layouts without much effort at all. For years, designers have struggled with different display values and positioning values, eventually coming to rely on frameworks to create complex sites. No more—enter the grid.

Grid is a layout engine that allows for page elements to be placed in a grid, in rows and columns. This means you can place elements exactly where you want them, by defining the rows of your page, the columns of your page, and then where in that grid the element fits. It's the easiest way to lay out your page, and it's supported in all newer browsers.

Terminology

Grid, like flexbox, defines some of its properties on the parent element and others on the children. The parent is the container of all the items to be placed in the grid and is what you set to display: grid;, while the children are the elements being stuffed into the grid.

Each grid is made up of invisible lines. When you're defining the lengths and widths of your rows and columns, you're really defining the lengths and widths of each line. The space between lines (what you'd think of as a row or a column) is called a track, and the intersection of each track is called a cell.

Defining the grid

To set up a grid, set the parent to display as one:

body { display: grid; }

Yes, the page <body> itself can be used as your grid container, and I'd recommend that if you're using grid to lay out an entire page. You can use any block-level element as the parent; it's best to keep it generic, like with a <main>. Again, the page <body> is probably your best bet.

The next step is to define the grid's rows and columns. For this, you'll use two properties: grid-template-rows and grid-template-columns. grid-template-rows works top to bottom (with the first in the list being row one), and grid-template-columns works left-to-right (and similarly, the first in the list will be considered column one).

body {
	display: grid;
	grid-template-rows: 300px 150px 600px 300px;
	grid-template-columns: 1fr 1fr 1fr; }

Both grid-template-rows and grid-template-columns take a list of unit lengths, just the same as you'd use to define an element's width. In the above example, the first row would be 300 pixels tall, the second row would be 150 pixels tall, the third row would be 600 pixels tall, and the fourth row would also be 300 pixels tall.

Introduced with CSS3 is a new unit for measuring length, the fractional unit (fr). The fractional unit is calculated by taking all the free space in the parent and dividing it by how many fractional units are in the list. This allows you to get exact fractions of space without having to calculate it out yourself. If you want three rows, each a third of the entire grid width, you'd declare:

grid-template-rows: 1fr 1fr 1fr;

The repeat shorthand works the same way.

grid-template-rows: repeat(3, 1fr);

You can also set the gutters between your rows and columns using the grid-gap property. If you're looking for a lot of white space between elements in your grid, you can use grid-gap to keep it consistent across the entire grid. grid-gap takes one to four values, much the same as margins or padding.

grid-gap: 15px 5px;

This declaration sets the space between each row as being fifteen pixels wide, while setting the space between each column as being five pixels wide. If grid-gap were set simply to 15px, both the space between each row and each column would be fifteen pixels.

Placing elements into the grid

To place an element into the grid, you'll need to specify the row and column the element starts and ends on. These are set per-child, using the grid-row and grid-column properties. Each take two values, the line the element should start on, and the line the element should end on. (Alternatively, the second value can set the number of tracks to span, but I'll discuss that in a moment.)

A <header> element slotted into the first row would be set as follows:

header { grid-row: 1 / 2; }

The <header> is set to start on the first row line and end on the second row line.

What if you wanted to have the <header> take up all three columns? For this, use a span value. By setting the second value in the declaration as a span value, you make that element span the length of the set number of tracks.

grid-column: 1 / span 3;

Don't confuse this example with the following:

grid-column: 1 / 3;

In the first example, the <header> starts on the first column line and spans three columns. In the second, the <header> starts on the first column line and ends on the third column line. In essence, the <header> in the first example is three cells wide, while in the second example, the <header> is only two cells wide.

grid-template-areas (and a word against it)

There is one other aspect to grid, and that's the use of grid-template-areas. Using it, you can name parts of your grid and slot elements in by name instead of by number.

body {
	display: grid;
	grid-template-rows: 300px 150px 600px 300px;
	grid-template-columns: repeat(3, 1fr);
	grid-gap: 15px 5px;
	grid-template-areas:
		"header header header"
		"nav nav nav"
		"sidebar main main"
		"footer footer footer" }

header { grid-area: header; }

You may be tempted to use this, as it's more visual than setting numerical values, but I'd recommend against it. It's a lot more unwieldy to write, and it doesn't work in Microsoft Edge. It is, however, technically valid, and the above example will make the <header> take up the first row, through all three columns.

Summary:

  1. Grid is a CSS layout engine that allows you to slot parts of a page into rows and columns you define. This allows for total control over your page layout, exactly as you want it.
  2. To define some terms related to grids:
    • The grid is made up of lines. When you're defining your grid's parameters, you're really defining the parameters of its lines.
    • The grid's rows and columns are called tracks.
    • The intersection of each track is called a cell. Think of the cells of a table in HTML.
  3. Some of the grid's properties go on the parent element (the grid itself), while others go in the children (the page elements that get placed into the grid).
  4. To create a grid, declare display: grid; on the parent (the <body> element will work fine), and then define the rows using grid-template-rows and the columns using grid-template-columns.
    • Pixel values, percentages, and fractional units all work when it comes to defining each track. Yes, you can mix them.
    • To define a grid with a 300px header row, a 150px navbar row, a 600px body row, and a 300px footer row, set grid-template-rows: 300px 150px 600px 300px;.
    • To define a grid with three equal-sized columns, set grid-template-columns: repeat(3, 1fr);.
    • You can also set the space between tracks using grid-gap. If you wanted 15px between the rows and 5px between the columns, you'd declare grid-gap: 15px 5px; on the parent.
  5. Then, to place elements into the grid, use grid-row and grid-column on each child. Both take two values each, the line the element starts on and the line the element ends on. Alternatively, the second value can be set to make the element span a number of tracks.
    • To place a <header> into the header row and span all three columns, declare header { grid-row: 1 / 1; grid-column: 1 / span 3; }.
    • grid-column: 1 / 3; is different from grid-column: 1 / span 3;! The former sets line three as where the header ends (making it only take up two cells), while the latter makes the header span three columns (and taking up three cells).
  6. While you can set names for parts of the grid using grid-template-areas, this is not recommended. Not only does it make your styling more complicated, but it also will not work properly in Microsoft Edge.

Further reading