Skip to content
Topic 14 of 15
Theory

CSS Grid

Why you need this

Flexbox lays elements out in one line (a row or a column). What if you need a grid — rows and columns at the same time? A photo gallery, a news tile wall, a "header — menu — text — footer" layout. That's what CSS Grid is for. If flex is beads on a string, grid is a chessboard.

Turning on a grid

<style>
  .grid {
    display: grid;
    grid-template-columns: 100px 200px 100px;
    gap: 10px;
  }
  .grid div { background: skyblue; padding: 20px; }
</style>
<div class="grid">
  <div>1</div><div>2</div><div>3</div>
  <div>4</div><div>5</div><div>6</div>
</div>

Result: two rows of three blocks; the middle column is twice as wide as the side ones; 10px between all blocks.

We didn't set any rows — they are created by themselves when the items don't fit in the first row. grid-template-columns lists the column widths separated by spaces.

The fr unit

fr (fraction) is a share of the free space:

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

Result: three columns, the middle one twice as wide; together they always take the full width of the container and adapt when the window gets narrower.

You can mix them: 200px 1fr — the left column is 200px, the right one gets the rest.

repeat and minmax

To avoid writing 1fr 1fr 1fr 1fr:

.grid { grid-template-columns: repeat(4, 1fr); }

minmax(min, max) sets a size "from … to". The famous "as many columns as fit" trick:

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

Result: cards no narrower than 200px; 5 in a row on a wide screen, 1 on a phone. Without a single media query.

Rows

.grid { grid-template-rows: 80px 1fr 60px; }

auto is a height based on the content. Rows and columns together form cells, and the lines between them are numbered from 1: three columns have lines 1, 2, 3, 4.

Spanning several cells

You can tell an item how many cells it takes:

.big {
  grid-column: span 2; /* 2 columns */
  grid-row: span 2;    /* 2 rows */
}
.wide {
  grid-column: 1 / 4;  /* from line 1 to line 4 = 3 columns */
}
.full {
  grid-column: 1 / -1; /* from the first to the last line — full width */
}

Result: .big is a 2×2-cell square and the other items flow around it; .full stretches over the whole row.

Named areas

The most visual way is to draw the layout in words:

.page {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "nav    main"
    "footer footer";
}
.page header { grid-area: header; }
.page nav    { grid-area: nav; }
.page main   { grid-area: main; }
.page footer { grid-area: footer; }

Result: a full-width header, below it a 200px menu on the left and the text on the right, a full-width footer at the bottom.

Each string in quotes is one grid row, and the words are cells. Identical neighbouring words merge into one area. A dot . is an empty cell. Areas must be rectangular.

Grid or Flexbox?

  • Flexbox — when items go in one line and their size depends on the content: a menu, buttons, a header.
  • Grid — when you need a grid with even columns and rows: a gallery, a page layout.

They are often combined: the page is a grid, the header inside it is flex.

How it works inside

The browser first builds an "invisible lattice" from grid-template-columns and grid-template-rows (fr columns share what remains after the pixels). Then it places the children into the cells: one by one from left to right, and items with span, line numbers or grid-area go to their own places. You can see the lattice in the developer tools: there is a grid badge next to the container.

Common mistakes

  1. display: grid on the children. The grid is turned on for the container.
  2. % mixed with gap. 25% 25% 25% 25% plus gap won't fit the width. fr doesn't have this problem.
  3. A typo in area names. grid-area: hedaer — the item silently drops into an automatic cell.
  4. A non-rectangular area. "a a" "a b" — an L-shaped area a isn't allowed, and the whole template breaks.
  5. Setting width on the items for the columns. Column widths are set by the container, not the items.

Cheat sheet

Property What it does
display: grid turn on the grid
grid-template-columns: 1fr 2fr columns
grid-template-rows: auto 1fr rows
repeat(3, 1fr) repeat
repeat(auto-fill, minmax(200px, 1fr)) as many as fit
gap: 10px gaps
grid-column: span 2 / 1 / -1 span 2 columns / the full width
grid-row: span 2 span 2 rows
grid-template-areas + grid-area a layout by named areas

Three columns

Easy+10 XP

Turn .gallery into a grid of three equal columns with a 10px gap.

Connect the connector to solve tasks

Task code runs on your own computer — faster and more reliable than in the browser. This needs the free CodeWithMe connector app. You only connect it once.

Looking for the connector on this computer…

  1. 1
    Download the connector for your system (Windows, macOS or Linux).Download the connectorOn the download page pick the file with your system in its name, e.g. windows-amd64.
  2. 2Run it and choose a folder for your solutions. It will install Python and Node.js there by itself when needed.
  3. 3
    Enter below the 6-digit code shown in the connector window (“Code for CodeWithMe”). If the browser asks about local network access — allow it.

The connector is open source (on GitHub), works only on your computer and runs code only after you enter the pairing code.