Overview of This Lesson

The CSS Grid allows you to lay out elements in rows and columns without having to fumble around with CSS positioning. A flex box allows you to make layouts in a single row or column that wraps when needed, whereas a CSS grid layouts can be used to create layouts that have both rows and columns. As with a flex box, a grid can be used to easily create responsive layouts without media queries.

Pre-Requisites

It's expected that you've already gone through the Responsive Design tutorial and the FlexBox tutorial before proceeding through this lesson.

Parts of the Responsive Grid

A grid is made up of rows and columns, similar to an HTML table, although a CSS grid is done with CSS and only the containers and items are defined with HTML. These rows and columns are referred to as Grid Tracks. Row tracks are the rows of items, and column tracks are the columns of items.

Grid Linesare the lines (which may be styled to be visible lines, or they may be invisible) between the row and column tracks in a grid. These also include the lines on the edges. Grid lines exist above and below each row track, and to the left and right of each column track, so this means they also appear above the first row, to the right of the last column, below the last row, and to the left of the first column.

grid tracks and grid lines
Grid Tracks are the row and columns that contain items. Grid Lines divide grid tracks from each other; the grid border is also made of grid lines.

Grid Lines are the lines that separate grid tracks. There is a grid line above the top row and below the last row, as well as between rows, so there are always #rows + 1 row lines in a grid. There is a grid line to the left of the first column, and to the right of the last column, as well as in between columns, so there are always #columns + 1 column lines.

All children defined inside a grid container become grid items. Grid items are placed into specific rows and columns of the grid.

Creating a Grid Container

The first step to coding a CSS Grid, is to first make your Grid Container. We can do this using the grid value of the display property. You can make any block element a grid container: my example below uses a <div> element but you can use whatever block element is appropriate for your page.

div.grid-container {
  display: grid;
}

The above code will define the <div class="grid-container"></div> as a CSS Grid container, ready to hold rows and columns of other elements. This grid is a block-level grid, so it will automatically include a new-line above and below the grid. You could also create an inline-grid as follows:

div.grid-container {
  display: inline-grid;
}

Using the value inline-grid; for the display property creates a grid container that is displayed as an inline element as opposed to a block element.

Once you have a grid container, you can then add grid items to it.

Adding Rows and Columns (Grid Tracks)

We use the properties grid-template-columns and grid-template-rows to define the row and column tracks in our grid container.

Use the grid-template-columns property to define the number and width of columns in your grid. The value of this property is a space-delimited list of values, one for each column track of your grid. The values can be any of the following:

For example, to create a grid with 3 columns of their preferred size and 1 column that is half the size of the grid width:

div.grid-container {
  display: grid;
  grid-template-columns: auto auto auto 50%;
}

In the above example, the last column will take up 50% of the grid container, and the first 3 columns will keep their preferred size, which may cause them to equally stretch across the remaining 50%, depending on the content of the columns.

CodePen: Grid Columns

See the Pen Grid: Columns by Wendi Jollymore (@ProfWendi) on CodePen.

The grid-template-rows property specifies the number and height of each row track in the grid. It works exactly like grid-template-columns except it works with rows/height instead of columns/width.

CodePen: Grid Rows

See the Pen Grid: Rows by Wendi Jollymore (@ProfWendi) on CodePen.

CodePen: Rows and Columns

This next example defines both row tracks and column tracks. Notice I defined 3 column tracks and only 2 row tracks, even though I have 11 grid items. The layout ends up with 4 row tracks (the last row is missing a 3rd column) but since I only defined the size of the first 2 rows, the last 2 rows retain their default height. Notice that only the first pair of rows are given the specified height (20vh or 20% of the viewport height for the first row, and 200 pixels for the 2nd row): this is not a repeating pattern. There is a way to repeat a row or column pattern using the repeat() function, as you'll see in a moment.

See the Pen Grid: Rows and Columns by Wendi Jollymore (@ProfWendi) on CodePen.

A New Unit of Measure: fr

The fr unit was introduced with the CSS Grid. It represents a fraction or portion of space. For example, a declaration of grid-template-columns: 1fr 2fr 1fr; means that the column tracks are divided up into 4 portions: the first and last columns each take up one portion, and the middle column takes up 2 portions. If the grid container was 1200 pixels wide, then the first and last columns would each be 300 pixels and the middle column would be 600 pixels.

You can combine the fr unit with other units, as you can see in this next CodePen:

CodePen: fr Units

See the Pen Grid: fr units by Wendi Jollymore (@ProfWendi) on CodePen.

Repeating a Pattern

As we saw in an earlier example, it would be nice if we could just repeat a pattern or rows and columns. This can be done using the repeat() function.

To use the repeat() function, pass it the pattern or row/column sizes you want to repeat. The first argument given to repeat() must be the number of times you want to repeat the pattern. This should be followed by a comma, and then by the pattern you want to repeat. For example, grid-template-columns: repeat(2, 100px 250px) will repeat a 100px column followed by a 250px column twice; it's basically the equivalent of grid-template-columns: 100px 250px 100px 250px; You could also say something like grid-template-rows: 10% repeat(2, 1fr 2fr); to have a row that is 10% of the container width, followed by 4 rows that alternate 1fr and 2fr. The equivalent would be 10% 1fr 2fr 1fr 2fr.

CodePen: repeat() function

See the Pen Grid: repeat() by Wendi Jollymore (@ProfWendi) on CodePen.

In the above example I used grid-template-columns: 25vw repeat(2, 1fr 2fr) to set the column widths to 25% of the viewport width for the first column, then 4 more columns that are 1fr, 2fr, 1fr, and 2fr.

For the rows, I used grid-template-rows: repeat(4, 100px 150px) to define 4 sets of two rows that are in a repeating pattern of 100px / 150px (so there would be 8 rows in total). Notice that since I only have enough grid items for 3 rows, there is a considerable amount of whitespace inside the grid: this is the space that would be occupied by the other 5 rows. Notice that if you change the rows to something such as grid-template-rows: repeat(4, 35% 60%), the height of the grid container changes: the percentage values 35% and 60% refer to the height of the grid container. It varies slightly from browser to browser, but generally the height of a container is computed after the items have been added to it. Since we only have 3 rows, the height of the grid container is computed for only those three rows; the other 5 rows have nothing in them, so they are counted as a height of 0. So 35% and 60% refer to a percentage of the computed container height with only three rows in it, not 8 rows.

Implicit Grid vs. Explicit Grid

Some rows and columns in your grid are the ones you've actually defined, but if you have more grid items than you have defined rows and columns, the browser will simply add rows/columns to fit those extra items. For example, in the Grid: Rows and Columns CodePen from earlier, we explicitly defined a grid with 3 columns and 2 rows, but we had 11 grid items, so there were an extra 5 grid items. These 5 grid items were added into 2 extra rows, using up 3 columns in the first extra row and 2 columns in the last extra row.

The rows/columns you've actually defined using grid-template-columns and grid-template-rows are referred to as the explicit grid. The rows and columns that are added to your grid by the browser are referred to as the implicit grid. Implicit grid rows and columns are always sized to their default sizes, and are not affected by any sizes you define in your explicit grid via grid-template-columns and grid-template-rows.

In that earlier CodePen example, the explicit grid is the 3-column, 2-row grid we defined. The implicit grid consists of the 5 cells in the last 2 rows that were added to fit the extra grid items.

You can define the default height of implicit rows and the default width of implicit columns using the grid-auto-rows and grid-auto-columns properties. Both properties take a single valid measurement, which will be the size of any implicit rows or columns. In the Codepen below, I set the height of implicit rows to be 15% of the viewport height.

CodePen: Implicit Grid

See the Pen Grid: Implicit Grid by Wendi Jollymore (@ProfWendi) on CodePen.

Placing Grid Items

So far we've been placing items in our grid in basic rows and columns. There are additional grid properties that allow you to place items over multiple rows/columns (similar to the HTML table rowspan and colspan attributes), and you can also align elements within their grid cell area.

Spanning Columns: grid-column-start, grid-column-end

The grid-column-start property is used to indicate at which column line a grid item should begin, and the grid-column-end property is used to indicate at which column line an element should end. Note that we're referring to column lines, not column tracks. Recall from earlier that the first column line is to the left of the first column track, and the last column line is to the right of the last column track, and there are also column lines between each column track. For example:

.grid-item {
  grid-column-start: 2;
  grid-column-end: 5;
}

In the example above, an element with class="grid-item" will span starting at column line 2 (which is to the left of the 2nd column track, or the right of the first column track), and will end at the 5th column line (which is to the right of the 4th column track). This causes the item to span across column tracks 2, 3, and 4.

Spanning Rows: grid-row-start, grid-row-end

The grid-row-start property is used to indicate at which row line a grid item should begin, and the grid-row-end property is used to indicate at which row line a grid item should end. Note that we're referring to row lines, not row tracks. Recall from earlier that the first row line is to above the first row track, and the last row line is below the last row track, and there are also row lines between each row track. For example:

.grid-item {
  grid-row-start: 2;
  grid-row-end: 5;
}

In the example above, an element with class="grid-item" will span starting at row line 2 (which is below the first row track, or above of the second row track), and will end at the 5th row line (which is to the below of the 4th row track). This causes the item to span along row tracks 2, 3, and 4.

CodePen: Row and Column Span

See the Pen Grid: Row/Column Span by Wendi Jollymore (@ProfWendi) on CodePen.

Shorthand Properties: grid-column, grid-row

The grid-column and grid-row properties are shorthand properties you can use for spanning rows and columns.

The grid-column property is a shortcut property for grid-column-start and grid-column-end. The syntax is as follows: grid-column: start / end; where "start" is the column line number the grid item should start in, and "end" is the column line number the grid item should end with. For example:

/* this item spans across columns 2 and 3 */
.grid-container > div {
  grid-column: 2 / 4;
}

The above is equivalent to using

grid-column-start: 2;
grid-column-end: 4;

You can use the value span followed by an integer number to indicate that the grid item should span across a certain number of columns. For example:

/* this item spans across columns 2, 3, and 4 */
.grid-container > div {
  grid-column: 2 / span 3;
}

The above is equivalent to using

grid-column-start: 2; 
grid-column-end: 5;
The grid-row property is a shorthand property for grid-row-start and grid-row-end. It works just like the grid-column property discussed earlier. For example:
/* this item spans across rows 3 and 4 */
.grid-container > div {
  grid-row: 3 / span 2;
}

The above is equivalent to using

grid-row-start: 3; 
grid-row-end: 5;

CodePen: Shorthand span properties

This example is the exact same as the previous one, but using shorthand properties to span rows and columns.

See the Pen Grid: Row/Column Span (shorthand) by Wendi Jollymore (@ProfWendi) on CodePen.

Grid Template Areas

Another way you can lay out items inside a grid is using grid template areas. The grid-template-areas property allows you to use a series of string values to define the areas of your layout. You can then assign a specific area to an element using the grid-area property.

The grid-template-areas property is used on the grid container element. You assign it a series of string values that depict the layout you want the grid container to have. Each part of your layout is assigned a unique identifier. For example, let's imagine I want to lay out a <main> element with a table taking up most of the page, with a navigation element on the left side and an <aside> on the right side. Below the table and the aisde, we'd also like to have a <section> with some content.

sketch of the main element layout described above
Sketch of the main element as described

Let's decide that we want the table to take up half the width of the screen, the navigation and the aside to each take up one quarter of the width. We also want the table and aside to take up a larger portion of the height than the section element does.

We might then decide to name our areas "nav", "table", "aside", and "section". The names you choose do not have to match the elements. I could have also called them something like "links", "info", "desc", etc. Choose names that make sense, because it will be easier to edit your layout later.

For this example, I might define my <main> element styling rule as:

main {
  display: grid;
  grid-template-areas: "nav table table aside"
                       "nav table table aside"
                       "nav section section section";
}

I purposely spaced out my code so that the set of strings visually looks similar to the layout sketch: this is not required, but does make it easier to read and understand. You'll see that I assigned grid-template-areas three sets of strings. You can separate your strings with a space or a newline with or without tabs/spacing but you can see that the way I did it is much easier to read and understand.

My first string "nav table table aside" creates a row that allocates a portion of width to the navigation element, two portions of width to the table, and one portion of width to the aside. The second string does the same, so this gives us two rows of content. The third string "nav section section section" lays out one portion of the width to the nav and three portions to the section. Since I used three strings, the height is divided up into three portions: the navigation gets all the height, the table and the aside each get two portions, and the section gets one portion of the height.

Once you've assigned your grid template areas, you assign an area name to each element that represents a grid item. In my example, I need to tell the <nav> element it belongs to the "nav" grid area, the <table> element that it belongs to the "table" grid area, the <aside> that it belongs to the "aside" grid area, and the <section> that it belongs to the "section" grid area. We do this by assigning the appropriate name to the grid-area property of the grid item:

nav {
  grid-area: nav;
}
table {
  grid-area: table;
}
aside {
  grid-area: aside;
}
section {
  grid-area: section;
}

Here's a CodePen that shows the entire example working:

See the Pen CSS Grid Areas Example 2 by Wendi Jollymore (@ProfWendi) on CodePen.

Here's another example that shows how you might lay out an entire page using a grid:

See the Pen CSS Grid Areas Example 2 by Wendi Jollymore (@ProfWendi) on CodePen.

The nice thing about using grid areas is that the size of the different areas will depend on the content inside the grid items. However, you are also able to add grid-template-columns and grid-template-rows with grid areas if you would like to fine-tune or have more control over the size of colums and rows. For example, I could modify the first example with the table by defining the preferred height of rows and columns:

main {
  display: grid;
  grid-template-areas:
    "nav table table aside"
    "nav table table aside"
    "nav section section section";
  grid-template-columns: 150px auto 200px;
  grid-template-rows: 2fr 2fr 1fr;
}

Here, I'm dividing up the height into five fractional units and giving the first two rows 2 each (total of 4) and giving the last row 1 fractional unit. I'm also specifying that the nav column be 150px, the aside column be 200px, and the table columns should take up whatever space is left. Notice that the widths are also dependent on the width of the content in the element, whether or not the screen width grows/shrinks, etc.

Here's the modified example in a CodePen:

See the Pen CSS Grid Areas Example 1 by Wendi Jollymore (@ProfWendi) on CodePen.

Aligning Rows, Columns, and Items

As with the Flex Box, there are several options for aligning rows, columns, and items in your grid:

Aligning Grid Items Horizontally: justify-items

The justify-items property allows you to align grid items along the horizontal axis, within their column tracks. Possible values include:

Aligning Grid Items Vertically: align-items

This is the same align-items property you learned to use with CSS Flex Box. It aligns the items vertically within the row track. It has the same values (start, end, center, baseline, normal, stretch (default).

CodePen: justify-items and align-items

See the Pen Grid: Align/Justify Items by Wendi Jollymore (@ProfWendi) on CodePen.

Aligning Grid Tracks Horizontally: justify-content

This is also the same justify-content property you used used with flex grid to align items on the horizontal axis. For a grid, the justify-content property aligns the column tracks horizontally. Note that it only works if the width of the grid container is more than the width of the actual grid of items.

The justify-content property has the same values you used before: auto, normal, start, end, center, stretch (default), baseline. However, rather than aligning each individual column track, it aligns all the column tracks together in the whole grid. For example, justify-content: center; will pack all the column tracks in the center of the grid, and justify-content: start; will pack all the row tracks on the left side of the grid. Values like space-around and space-between will add any used space around/between individual columns.

Aligning Grid Tracks Vertically: align-content

The align-content uses the same values you learned when you used it with the flex box (center, start (default), end, baseline, space-between, space-around, stretch). This property vertically aligns the row tracks in your grid, if there is enough vertical space for them to use (doesn't work if the height of the row is not more than the height of the grid item).

As with justify-content, align-content aligns all the row tracks together, so align-content: start; will pack all the rows near the top of the grid and align-content: center; will pack all the rows in the center of the grid.Values like space-around and space-between will add any used space around/between individual rows.

CodePen: Aligning Grid Tracks

See the Pen Grid: Align/Justify Tracks by Wendi Jollymore (@ProfWendi) on CodePen.

Aligning Individual Grid Items

As with the Flex Box, you can use the align-self and justify-self to align individual grid items differently from the grid default. The align-self property uses the same values as align-items, and justify-self has the same values as justify-items.

The align-self property override's the grid's align-items property for an individual item. This means that you can use it to vertically align an individual item in a manner that's different from what you set for the entire container using align-items (or override the default, if you didn't set align-items).

The values for align-self include:

The justify-self property overrides the grid's justify-items property for an individual item. This means that you can use it to horizontally align an individual item in a manner that's different from what you set for the entire container using justify-items (or override the default, if you didn't set justify-items).

The values for justify-self include:

CodePen: Align Individual Items

See the Pen Grid: Align/Justify Individual Items by Wendi Jollymore (@ProfWendi) on CodePen.

Summary of Alignment Properties

It can be difficult to remember the different alignment properties, especially as the pertain to either Flex Box or Grid, so this table should help:

Flex/Grid Alignment Properties
Properties Flex Box Grid
justify-items n/a items on horizontal axis within a column
align-items cross axis items on vertical axis within a row
justify-content main axis column tracks on horizontal axis
align-content aligns flex lines (vertical for row, horizontal for col) row tracks on vertical axis
justify-self n/a individual item horizontally
align-self individual item on cross axis individual item vertically

Row and Column Spacing

In between grid rows are row gaps, and in between grid columns are column gaps. You can define how much space to place between rows and columns by using one of the following properties in your grid container:

Each of the grid gap properties accepts any valid size/length measurement, including percentage. The default value for each is 0.

CodePen: Grid Gap

See the Pen Grid: Grid Gap by Wendi Jollymore (@ProfWendi) on CodePen.

Grid Layout vs FlexBox

So which one should you use, the Flex Box or the Grid? Here are some links and pointers to help you decide.

Note that the CSS FlexBox and CSS Grid can be combined! A grid item can be a flex container, and a flex item can be a grid container.