Skip to content
wannacode

Grid: rows and columns

In short: CSS Grid lays items out in rows and columns at once: columns with fr and gap, a catalogue with repeat(auto-fill, minmax()) and a page layout with grid-template-areas.

Problem

The last product is huge

The catalogue uses flex-wrap from the last lesson. Four products: three fit on the first line, and the fourth is alone on the second line and as wide as the whole line.

HTML, CSS, JS

This is not a bug in flexbox. Each line of a flex container shares its own free space and knows nothing about the line above. The second line has one product, so it takes everything: 768px. We need something that draws the columns once for the whole catalogue.

The idea

Rows and columns

Grid is a layout in two dimensions: the container draws columns and rows, and the items go into the cells one by one, row by row.

.catalog {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 24px;
}
  • display: grid makes the element a grid container, and its children are grid items.
  • grid-template-columns says how many columns there are and how wide each is: 200px 1fr is a 200px column and a column that takes the rest.
  • fr is a share of the free space, after the sized columns and the gaps are taken out. 1fr 2fr 1fr is 1 : 2 : 1.
  • repeat(3, 1fr) is the same as 1fr 1fr 1fr.
  • gap is the space between the columns and between the rows.

The difference from flexbox: with flex the items decide how wide they are, and each line is separate. With grid the container decides the columns, and the items only fill them. So the last product stays in its column.

Try it

Three columns

Make the catalogue a grid with three equal columns and a 24px gap. The catalogue is up to 720px, so every card, the last one too, has to be (720 − 2 × 24) : 3 = 224px.

HTML, CSS, JS

The idea

As many as fit

Three columns are fine on a computer. On a phone they are 100px each, and the product cannot be read. We do not want to give the number but a rule: "columns of at least 200px, as many as fit".

grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  • minmax(200px, 1fr): the column is at least 200px and at most one share.
  • auto-fill instead of a number: the browser puts as many columns of the smallest width as fit, together with the gaps.
  • Then the rest is shared equally (1fr), and the columns grow to the end of the row.

See it

See how they are counted

One and the same rule in a catalogue of 960, 680 and 328px.

.catalog {
display: grid;
grid-template-columns:
repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
Step by step, in words
  1. The catalogue is a grid. The columns are not given as a number but as a rule: as many as fit, each at least 200px.
  2. A catalogue 960px wide. The browser puts columns of 200px with a 16px gap while they fit: 4 × 200 + 3 × 16 = 848px. A fifth would reach 1064px: it does not fit.
  3. 960 − 848 = 112px are left. 1fr shares them equally: every column is (960 − 3 × 16) : 4 = 228px.
  4. At 680px three columns fit (3 × 200 + 2 × 16 = 632). A fourth would need 848. Each becomes (680 − 32) : 3 = 216px.
  5. At 328px, a phone, one fits: two would need 416px. It takes the whole width: 328px.
  6. One rule, three layouts. The number of columns follows the width of the catalogue, with no media queries. The products fill the columns row by row.

The same catalogue as a page, first on a phone (360px), then on a computer (1000px). The code is the same.

HTML, CSS, JS
HTML, CSS, JS

The columns depend on the width of the catalogue, not of the screen. A catalogue in a narrow column of the page has fewer columns even on a big screen.

Try it

One rule for both places

The page has a catalogue and a narrow column "Also bought" (220px). Both are .catalog with flex-wrap, and the last product in the catalogue is too wide. Change the rule for .catalog: grid, columns of at least 200px, as many as fit, stretched to the end. The check expects 3 columns in the catalogue, each 208px, and 1 column of 220px on the right.

HTML, CSS, JS

The idea

Areas of the page

Grid also lays out the page itself: the header, the filters on the left, the catalogue, the footer. The areas can be drawn with names:

.page {
display: grid;
grid-template-columns: 220px 1fr;
grid-template-areas:
"header header"
"filters main"
"footer footer";
gap: 16px;
}
header { grid-area: header; }
.filters { grid-area: filters; }
  • Every line in quotes is a row of the grid, and every word is a cell. One word in two cells next to each other makes an area that takes both: the header is over two columns.
  • grid-area: header puts the element into the area with that name.
  • Every row has to have as many cells as there are columns, and an area has to be a rectangle.

Without names, an item is placed by the numbers of the lines between the columns: grid-column: 1 / 3 is from the first to the third line (two columns), and grid-column: 1 / -1 goes to the last line. grid-column: span 2 takes two columns wherever the browser puts it.

Try it

The page

Lay out the page (900px) with grid-template-areas: the header at the top over the whole width, under it the filters on the left (220px) and the catalogue on the right, the footer at the bottom over the whole width. The gap is 16px.

HTML, CSS, JS

Try it

Find the bug

The page fell apart: the header, the filters, the catalogue and the footer are on top of each other. The console has no error. Which line is the cause?

Pick the line with the bug.

More precisely, if you are curious

Implicit rows. grid-template-columns and grid-template-rows describe the explicit grid. If there are more items, the browser adds rows by itself. They are implicit and are auto, as tall as the content. Their height is set with grid-auto-rows.

auto-fill and auto-fit. The difference shows when there are fewer items than columns. In a 960px catalogue with two products auto-fill keeps the four columns, and the products are 228px each. auto-fit drops the empty columns, and the two products become 472px each.

fr and the content. 1fr is minmax(auto, 1fr): the column does not get narrower than the longest word in it. If one long word stretches the column, minmax(0, 1fr) stops it.

Grid or flex. Flexbox is for one axis: a header, a row of buttons, a line in the cart. Grid is for two: a catalogue, a page, a dashboard. They often go together: the page is a grid, and the header in it is flex.

More. grid-auto-flow: dense fills empty cells with later items, but it mixes up the order on the screen compared to the tree. subgrid lets a nested grid use the columns of its parent.

Exercise

The product of the week

Make the catalogue (900px) a grid: columns of at least 200px, as many as fit, gap 16px. The product of the week is first and takes two columns. All rows are 160px tall, including the ones the browser adds by itself. The check expects 4 columns of 213px, the product of the week 442px wide and the last product 160px tall.

HTML, CSS, JS

Test

Test yourself

1. A 700px catalogue has grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)) and gap: 20px. How many columns does it have?
2. When is grid the better choice over flexbox?
3. What does grid-column: span 2 do?
4. The grid has grid-template-rows: 160px, and the products are on three rows. How tall are the second and third rows?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·