The grid lines
Here's the number-one confusion with Grid: you count the lines, not the cells. A grid of N columns has N+1 vertical lines, numbered from 1. Three columns are delimited by lines 1, 2, 3 and 4 (four lines for three gaps, like the posts of a fence). An item is placed by stating between which lines it starts and ends.
.featured {
grid-column: 1 / 3; /* from line 1 to line 3: spans 2 columns */
grid-row: 1 / 2; /* from line 1 to line 2: one row */
}
span: occupy several cells
If you don't want to count lines, use the keyword span to state
how many tracks to occupy starting from where the item begins:
.featured {
grid-column: span 2; /* spans 2 columns, wherever it starts */
grid-row: span 2; /* and 2 rows */
}
This is perfect for that "featured photo" that fills half the gallery, without tying yourself to specific positions: reorder the cards and the featured one keeps its size without you touching a single line number.
⚠️ CLASSIC TRAP:
span 2isn't "go to line 2", it's "occupy 2 tracks". If you mixgrid-column: 2 / span 2it counts from line 2 and moves forward 2 slots. Don't confuse the line number with the number of cells to occupy.
Named areas: the visual layout
The most readable way to lay out a page is to draw it with
grid-template-areas. You define the grid as a "map" of names and then
assign each item to its zone with grid-area:
.page {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"menu content"
"footer footer";
gap: 12px;
}
.header { grid-area: header; }
.menu { grid-area: menu; }
.content { grid-area: content; }
.footer { grid-area: footer; }
The repeated name (header header) makes that zone span several
columns. A dot (.) leaves a cell empty. The big advantage: the CSS reads like
an ASCII drawing of the page, and to change the whole layout you only rewrite the map.
⚠️ CLASSIC TRAP: the "map" must be a perfect rectangle. Every row needs the same number of columns, and each area has to form a rectangular block (no L-shaped zones). If one row is missing a name, the whole rule is silently ignored and you'll go crazy hunting for the bug.