CSS

Deep Dive into CSS Grid

March 7, 2023

This tutorial will dive deep into the CSS Grid Layout exploring almost all properties and features. In the end, you will be fully equipped to tackle any layout with this great CSS addition.

Terminology: Grid

A grid is a two-dimensional grid system. It can be used to build complex layouts as well as small user interfaces.

Property: Display

To make an element a grid, set its display property to grid.

.grid-to-be {
    display: grid;
}

Doing this makes .grid-to-be a grid container and its children grid items.

Terminology: Grid Tracks

Grid Tracks are the spaces between two Grid Lines. The rows and columns in a Grid are Grid Tracks.

Property: grid-template-columns

We can create columns by using the grid-template-columns property. To define columns set this grid-template-columns property to column sizes in the order that you want them in the grid to appear. Let’s have a look:

.grid {
    display: grid;
    grid-template-columns: 100px 100px 100px;
}

This defines three 100px width columns. All grid items will be arranged, in order, in these columns. The row height will be equal to the height of the tallest element in that row, but this can be changed with grid-template-rows.

Note that, with only columns and no rows defined, elements fill columns and then flow back in rows. This is because of the implicit grid that Grid has created with grid lines and grid tracks.

Property: grid-template-rows

grid-template-rows is used to define the number and size of rows in a grid. It is similar in syntax to grid-template-rows.

.grid {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 100px 100px 100px;
}

Only having the grid-template-rows property on without grid-template-columns will result in the column width being equal to the width of the widest element in that row.

Property: grid-template

grid is shorthand for three properties: grid-template-rows, grid-template-columns, and grid-template-areas.

The way you use it is like this:

.grid {
    grid-template:
        "header    header     header"  80px
        "nav       article    article" 600px
        / 100px 1fr;
}

You define the template areas like you normally would, place the width of each row on its side and then finally place all the column widths after a forward slash. Like before, you can place all of it on a single line.

Data Type

The fr unit is a new unit created for CSS Grid Layout. The fr unit helps to create flexible grids without needing to calculate percentages. 1fr represents one fraction of the available space. The available space is divided into the total number of fractions defined. So, 3fr 4fr 3fr divides the space into 3+4+3=10 parts and allocates 3, 4, and 3 parts of the available space for the three rows/columns respectively. For example:

.grid {
    display: grid;
    grid-template-columns: 3fr 4fr 3fr;
}

If you mix fixed units with flexible units, the available space for the fractions is calculated after subtracting the fixed space. Let’s look at another example:

.grid {
    display: grid;
    grid-template-columns: 3fr 200px 3fr;
}

The width of a single fraction is calculated like this: (width of .grid - 200px) / (3 + 3). The space of the gutters, if any present, would have also been subtracted initially from the width of .grid. This is the difference between frs and %s that percentages don’t include the gutter that you define with grid-gap.

Here 3fr 200px 3fr is essentially equal to 1fr 200px 1fr.

Explicit grid and Implicit grid

The explicit grid is the one created with properties grid-template-rows and/or grid-template-columns. The implicit grid consists of the grid lines and grid tracks that Grid creates to hold items outside of the manually created grid with the grid-template-* properties.

Auto-placement

When we create a grid like this:

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

Even though we have only defined the columns, individual cells that are direct children of .grid lay themselves out in rows. This is because of the rules of auto-placement that are part of Grid.

Property: grid-auto-columns

To define the size of the created columns, implicitly-created grid column tracks, which were not defined by grid-template-columns, use the grid-auto-columns property. The default value is auto; you can set it to any value you want.

.grid {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-auto-columns: 50px;
}

Property: grid-auto-rows

grid-auto-rows works similar to grid-auto-columns. To define the size of the created rows, implicitly-created grid row tracks, which were not defined by grid-template-rows, use the grid-auto-rows property. The default value is auto; you can set it to any value you want.

.grid {
    display: grid;
    grid-template-rows: 100px 100px 100px;
    grid-auto-rows: 50px;
}

Property: grid-auto-flow

The grid-auto-flow property controls how grid cells get flowed into the grid: in rows or columns. The default value is row.

.grid {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-auto-flow: column;
}

The grid cells in the above grid fill columns one by one until no items are left.

Line-based Placement

Placing items in a grid using line numbers is called line-based placement.

Property: grid-row-start

If you want a specific grid item to start on a particular row line then you can have something like this:

.grid-item {
    grid-row-start: 3;
}

Property: grid-row-end

If you want a specific grid item to end on a particular row line then you can have something like this:

.grid-item {
    grid-row-end: 6;
}

Property: grid-column-start

If you want a specific grid item to start on a particular column line then you can have something like this:

.grid-item {
    grid-column-start: 3;
}

Property: grid-column-end

If you want a specific grid item to end on a particular column line then you can have something like this:

.grid-item {
    grid-column-end: 6;
}

Property: grid-row and grid-column

You may use the grid-row and grid-column properties to manually place and size grid items. Each property is the shorthand for their respective star and end properties: grid-row-start, grid-row-end, grid-column-start, and grid-column-end.

Us a forward slash ”/” to separate the start and end values:

.grid-item {
    grid-column: 3 / 5;
    grid-row: 2 / 7;
}

Property: grid-area

You can use grid-area as a shorthand for both grid-row and grid-column. It works like this: / / / :

.grid-item {
    grid-area: 2 / 3 / 7 / 5;
}

This code behaves the same as the code in the previous heading.

Spanning an element across the grid

To span an element across the grid, you can use the grid-row or grid-column property. Set the starting line 1 and the ending line -1. Here 1 means the leftmost grid line and -1 means the rightmost grid line in the relevant axis. This would be opposite, in a right to left writing script, that is 1 meaning the rightmost line and -1 meaning the leftmost line.

.grid-item-weird {
    grid-column: 1 / -1;
}

If you want a single item to take up the entire grid, you can do this to both grid-row and grid-column:

.grid-item-weird {
    grid-row: 1 / -1;
    grid-column: 1 / -1;
}

Or simply:

.grid-item-weird {
    grid-area: 1 / 1 / -1 / -1;
}

Keyword: span

Instead of explicitly defining the line numbers when using grid-row and grid-column, you may use the span keyword to state how many rows or columns the item should cover:

.grid-item {
    grid-column: 3 / span 2;
}

You may also tack the item onto the ending line and span it across in the other direction. The code below achieves the same result as above:

.grid-item {
    grid-column: span 2 / 5;
}

You may use span for rows the same way.

Terminology: Grid Cell

Grid Cell is the space between four intersecting Grid Lines just like a table cell.

Terminology: Grid Areas

Grid Areas are grid cell(s) taking up a rectangular area on the grid. They are created using named grid areas or line-based placement.

Property: grid-template-areas (& grid-area)

Instead of placing and sizing individual grid items with things like span, grid-column, etc, you may use what’s called Template Areas. The grid-template-areas allows you to name areas of a grid so that they may further be filled up by grid items.

.grid {
    display: grid;
    grid-template-columns: 100px 1fr 100px;
    grid-template-rows: 100px 800px 100px;
    grid-template-areas:
        "header     header   header"
        "sidebar-1  content  sidebar-2"
        "footer     footer   footer"
}

Here a single pair of quotes represents a row of the grid. You could have it all in a single line and not align the columns, but I have done just so that it looks cleaner. So, first I have defined three columns and three rows and then named each cell. By having “header” repeated three times in the first row, what I’m telling CSS to do is to cover that whole thing with the grid item named header. The rest is likewise.

Here’s how you name each grid item to have the space that was defined for it using grid-template-areas:

.header {
    grid-area: header
}

.sidebar-1 {
    grid-area: sidebar-1
}

.content {
    grid-area: content
}

.sidebar-2 {
    grid-area: sidebar-2
}

.footer {
    grid-area: footer
}

Nothing could ever be easier than that, especially other CSS methods for laying out content.

Previously, you have seen that grid-area is used for line-based positioning too.

You may use a dot if you want to leave a cell empty:

.grid {
    display: grid;
    grid-template-columns: 100px 1fr 100px;
    grid-template-rows: 100px 800px 100px;
    grid-template-areas:
        "header header header"
        "sidebar content sidebar"
        "footer footer ."
}

Here the footer ends with the second column.

Property: grid-template

grid is shorthand for three properties: grid-template-rows, grid-template-columns, and grid-template-areas.

The way you use this is like this:

.grid {
    grid-template:
        "header    header     header"  80px
        "nav       article    article" 200px
        / 100px auto;
}

You define the template areas like you normally would, place the width of each row on its side and then finally place all the column widths after a forward slash. Like before, you can place all of it on a single line.

Function: repeat()

The repeat() function helps to make grid tracks listings a little non-redundant and adds a bit of semantic layer to them. It is quite easy and intuitive to use. Let’s have a look:

.grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr); // this is the same as 1fr 1fr 1fr
}

You may repeat a certain pattern of track listing, as well, like this:

.grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr 2fr); // this is the same as: 1fr 2fr 1fr 2fr 1fr 2fr
}

The repeat() doesn’t need to be the only part of the value. You may add other values before and after it. For example: grid-template-columns: 2fr repeat(5, 1fr) 4fr;.

Property: grid

grid is shorthand for six properties: grid-template-rows, grid-template-columns, grid-template-areas, grid-auto-rows, grid-auto-columns, and grid-auto-flow.

First of all, you may use like grid-template like this (the previous example):

.grid {
    grid:
        "header    header     header"     80px
        "nav       article    article"    200px
        / 100px auto;
}

Second of all, it is not what it looks like: That is, grid is not like the property css:

Yes, you read that right: a property called css. The Shorthand for all CSS properties. I came across it in a revelatory experience during transcendental meditation involving CSS and whatnot. But I won’t teach you how to use it. I’m keeping it for a future tutorial. Till then keep moving high on the ladder to CSS enlightenment.

Third of all, you use grid a certain way. You can combine grid-template-rows with grid-auto-columns or you can combine grid-auto-rows with grid-template-columns. The syntax of these are pretty simple:

.grid-item {
    /_ grid: <grid-template-rows> / <grid-auto-columns>; _/
    /_ grid: <grid-auto-rows> / <grid-template-columns>; _/
}

For example:

.grid-item-1 {
    grid: 50px 200px 200px/ auto-flow 60px;
}

.grid-item-2 {
    grid: auto-flow 50px / repeat(5, 1fr);
}

Note that you actually use the keyword auto-flow before the value.

Terminology: Gutters

Gutter is the space that separates grid rows and grid columns individually. grid-column-gap, grid-row-gap, and grid-gap are the properties used to define gutters.

Property: grid-row-gap

grid-row-gap is used to define the space between individual grid rows. It works like this:

.grid {
    display: grid;
    grid-template-rows: 100px 100px 100px;
    grid-row-gap: 10px;
}

This spaces out the grid rows 10 pixels apart from each other.

Property: grid-column-gap

grid-column-gap is used to define the space between individual grid columns. It works like this:

.grid {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-column-gap: 10px;
}

This spaces out the grid columns 10 pixels apart from each other.

Property: grid-gap

grid-gap is the shorthand property that combines grid-column-gap and grid-row-gap. One value defines both gutters. For example:

.grid {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 100px 100px 100px;
    grid-gap: 10px;
}

Property: order

We can control the order of grid cells using the order property. Let’s look at the following example:

.grid {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 100px 100px 100px;
    grid-gap: 10px;
}

.grid .grid-cell:nth-child(5) {
    order: 1;
}

Above, the fifth grid cell is placed last in the grid because the other grid cells have no order defined at all. If defined, then the numerical order would be followed. Two or more grid cells can have the same order. The ones with the same order or no order at all are placed according to the logical order of the HTML document. Let’s have a look here:

.grid {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 100px 100px 100px;
    grid-gap: 10px;
}

.grid .grid-cell {
    order: 1
}

.grid .grid-cell:nth-child(5) {
    order: 2;
}

The above example produces identical results to the previous example.

Function: minmax()

The minmax() function is new to CSS Grid Layout. This function gives us a way to specify the minimum as well as the maximum size for grid tracks.

Let’s have a look at the following example:

.grid {
    display: grid;
    grid-template-columns: 1fr minmax(50px, 100px) 1fr;
}

With the above code in effect, on reducing the window width, the middle column retains its 100px width until the first and last columns are reduced to the width of their content. This is especially useful for making responsive layouts.

Keyword: auto

If the parent container’s dimension is fixed, like a fixed width, the auto keyword as the width of a grid item will make the item fill the whole width of the container. In the case of multiple items, the space is divided just like frs. But if auto is used with fr, auto behaves as the width of the content of that item and the rest of free space is divided to make up frs.

Function: fitcontent()

The fitcontent() function is used when you want the width/height to behave like auto but also have a maximum width/height in case you don’t want it to get all the way that big.

.grid-item {
    width: fitcontent(200px);
}

Here it will, on the minimum side fit the content and on the maximum be as big as 200px.

Keyword: auto-fill

You can use the auto-fill to fill the relevant axis (row or column) with the most number of grid tracks without overflowing. The way you achieve this is using the repeat() function:

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, 50px);
}

But this would reduce the flexibility of individual tracks. You can have both auto-fill functionality and flexibility by using minmax() with it.

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
}

This way, you can have at least one column and at most all columns of 50px in a particular browser width.

Note that auto-fill* creates grid tracks even though they may not be filled with cells.

auto-fit

auto-fit behaves the same as auto-fill except that it collapses all empty repeated tracks. An empty track is one with no grid items placed in it or spanning across it.

dense

With the help of the dense keyword, you can backfill items into empty grid cells which were created because of weird things you were trying to do like spanning and whatnot. Any span, you may use the dense keyword with grid-auto-flow like this:

.grid {
    display: grid;
    grid-template-column: repeat(auto-fill, minmax(50px, 1fr));
    grid-auto-flow: dense;
}

You can use this with an image gallery but be careful with something like a form. You mostly want the form sub-elements in a specific order.

Browser Support

At the time of this writing, there is good browser support for CSS Grid Layout. According to caniuse.com, all major browsers support CSS Grid Layout except Internet Explorer 11 which has partial support with -ms- prefix and Opera Mini having no support at all.

Conclusion

CSS Grid allows us to make layouts with more control, ease and speed than previous method systems. In this tutorial, we learned all major elements of Grid which includes creating tracks, positioning and sizing cells, and making the grid fluid and responsive with keywords like auto-fill and functions like minmax().

© All rights reserved — cs.fyi