This blog post contains my notes from the great interactive video course Learn CSS Grid for free authored by Per Harald Borgen. Please watch the video courses. They explain CSS Grid in a very easy to understand way.

The videos are interactive. The watcher can edit the source code at any time directly on the video screen and see the effects immediately.

Table of Contents

v01: Stacking without CSS Grid

cat cssgrid01.html
  ##> <html>
  ##>     <head>
  ##>         <link rel="stylesheet" href="basic.css">
  ##>         <style>
  ##>             .container {
  ##>                 display: grid;
  ##>             }
  ##>         </style>
  ##>     </head>
  ##>     <body>
  ##>         <div class="container">
  ##>             <div>1</div>
  ##>             <div>2</div>
  ##>             <div>3</div>
  ##>             <div>4</div>
  ##>             <div>5</div>
  ##>             <div>6</div>
  ##>         </div>
  ##>     </body>
  ##> </html>
  ##> 

v02: Basic Layout with CSS Grid

Sizes of columns and rows are specified with: grid-template-columns and grid-template-rows

            .container {
                display: grid;
                grid-template-columns: 100px auto;
                grid-template-rows: 50px 50px 100px;
                grid-gap: 3px;
            }

Note that, auto makes the second column responsive.

Let’s convert from 3 columns x 2 rows to 2 columns x 3 rows:

                grid-template-columns: 100px auto;
                grid-template-rows: 50px 50px 100px;

We can move the style code into a separate css file:

        <link rel="stylesheet" href="cssgrid04.css">
cat cssgrid04.css
  ##> .container {
  ##>     display: grid;
  ##>     grid-template-columns: 100px auto;
  ##>     grid-template-rows: 50px 50px 100px;
  ##>     grid-gap: 3px;
  ##> }
  ##> 

The result is the same.

v03: Fraction Units and repeat()

2fr column is twice as large as 1fr column.

    grid-template-columns: 1fr 2fr 1fr;
    grid-template-rows: 50px 50px;

To make all columns equal in width, we can either do this:

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

or this:

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

Let’s make 6 columns:

    grid-template-columns: repeat(6, 1fr);
    grid-template-rows: 50px 50px;

We can use repeat() also with rows:

grid-template-rows: repeat(2, 50px);

As shorthand, we can specify column and row sizes in one line:

grid-template: repeat(2, 50px) / repeat(3, 1fr);

v04: Positioning items

cat cssgrid09.html | sed -n '/container/,+5 p'
  ##>         <div class="container">
  ##>             <div class="header">HEADER</div>
  ##>             <div class="menu">MENU</div>
  ##>             <div class="content">CONTENT</div>
  ##>             <div class="footer">FOOTER</div>
  ##>         </div>
grid-template: 40px 40px / repeat(2, 1fr);

Let’s give content more area to expand:

grid-template: 40px 200px 40px / repeat(2, 1fr);

But we need to separate content section from footer section.

.header {
  grid-column-start: 1;
  grid-column-end: 3;
}

.menu {}

.content {}

.footer {
  grid-column-start: 1;
  grid-column-end: 3;
}

Let’s make content section wider too:

grid-template: 40px 200px 40px / 1fr 4fr;

Alternatively, we can write in shorthand form:

grid-column: 1 / 3;

Or:

grid-column: 1 / span 2;

Or:

grid-column: 1 / -1;

-1 is useful if we may change number of columns later.

Let’s use 12 column layout:

grid-template-columns: repeat(12, 1fr);

We don’t need to change the followings:

grid-column: 1 / -1;

But we need to specify the positioning of content

.content {
  grid-column: 2 / -1;
}

Now, let’s change the overall layout. Let the menu section start from the top and slide header section beside it.

To do it, header should start from 2. column border and menu should start from 1. row border:

.header {
  grid-column: 2 / -1;
}

.menu {
  grid-row: 1 / 3;
}

v05: Template Areas

“Template Area” feature allows to experiment with different layouts very rapidly.

cat cssgrid13.css
  ##> .container {
  ##>   height: 100%;
  ##>   display: grid;
  ##>   grid-template-columns: repeat(12, 1fr);
  ##>   grid-template-rows: 40px auto 40px;
  ##>   grid-gap: 3px;
  ##>   grid-template-areas:
  ##>     "h h h h h h h h h h h h"
  ##>     "m c c c c c c c c c c c"
  ##>     "f f f f f f f f f f f f"
  ##> }
  ##> 
  ##> .header {
  ##>   grid-area: h;
  ##> }
  ##> 
  ##> .menu {
  ##>   grid-area: m;
  ##> }
  ##> 
  ##> .content {
  ##>   grid-area: c;
  ##> }
  ##> 
  ##> .footer {
  ##>   grid-area: f;
  ##> }
  ##> 
  ##> 

The layout of the page is specified with the following expression:

grid-template-areas:
  "h h h h h h h h h h h h"
  "m c c c c c c c c c c c"
  "f f f f f f f f f f f f"

h m c f are header menu content footer sections respectively.

To experiment with different layouts, let’s change top h and bottom f with m:

grid-template-areas:
  "m h h h h h h h h h h h"
  "m c c c c c c c c c c c"
  "m f f f f f f f f f f f"

. dots will make blank cells

But all sections should be rectangular.

grid-template-areas:
  "m . . h h h h h h h h h"
  "m c c c c c c c c c c c"
  "m f f f f f f f f f f f"

v06 Auto-fit and minmax

auto-fit adjusts the number of columns according to the size of the window:

grid-template-columns: repeat(auto-fit, 100px);

Instead of 100px we can use 1fr together with minmax. A column will be at least 100px and at max 1fr.

grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));

v07 Implicit rows

Note that, in the previous examples the rows after second row have a broken height. Let’s define default size for all rows:

grid-auto-rows: 100px;

instead of:

grid-template-rows: repeat(2, 100px);

–>

grid-auto-rows: 100px;

v08 An awesome image grid

@tbd

.horizontal {
  grid-column: span 2;
}

.vertical {
  grid-row: span 2;
}

.big {
  grid-column: span 2;
  grid-row: span 2;
}

blank spots

grid-auto-flow: dense;

source order independence

v09 Named Lines

Until now, we specified the layout using the border line numbers such as 1/3 where 1 is the starting column border line and 3 is the ending column border line:

.container {
  display: grid;
  grid-template-columns: 1fr 5fr;
  grid-template-rows: 40px auto 40px;
}
.header {
  grid-column: 1 / 3;
}
...

Now, instead of line numbers we can give names to the lines:

grid-template-columns: [main-start] 1fr [content-start] 5fr [content-end main-end];

Here, [main-start] is the name of first line. [content-start] is the name of second line.

Note that, third line has two names: content-end and main-end.

So, instead of 1 / 3 we can say main-start / main-end

.header {
  grid-column: main-start / main-end;
}

.content {
  grid-column: content-start / content-end;
}

We can further simplify these expressions by eliminating -start and -end words:

.header {
  grid-column: main;
}

.content {
  grid-column: content;
}

We can do the same also for naming row lines:

.container {
  grid-template-columns: [main-start] 1fr [content-start] 5fr [content-end main-end];
  grid-template-rows: [main-start] 40px [content-start] auto [content-end] 40px [main-end];
  ...

.footer {
  grid-column: main;
}

We can still make one more simplification. Note that, content section’s 4 borders are named as content. So we can say:

.content {
  grid-area: content;
}

But we cannot do this for footer section. Because footer’s starting row is named as content-end whereas its ending row is named as main-end. Since, their names are different, we cannot specify it as a grid-area.

v10: justify-content and align-content

Use justify-content to justify content as start, center or end:

.container {
  justify-content: end;
  ...

align-content aligns the elements vertically:

align-content: end;

To distribute elements around space use: space-evenly space-between space-around

justify-content: space-between;

v11: auto-fit vs. auto-fill

There is a very slight difference between auto-fit and auto-fill:

.container {
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
  grid-template-rows: repeat(2, 100px);
}

.container2 {
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
  grid-template-rows: repeat(2, 100px);
}

When we increase the width, both behave similarly:

But if we keep expanding, then they differ: