"The CSS reads like a sketch of the layout. That's not a metaphor — that's literally what the syntax is."
The Idea
Most layouts can be described as named regions: header, sidebar, main, footer. grid-template-areas lets you draw that map directly in the CSS using strings, where each string is a row and each word is a cell name. Items then reference areas by name with grid-area.
The result is the most readable layout syntax CSS has — the CSS literally looks like a sketch.
The Syntax
On the grid container:
.layout {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
Each string is one row. Within a string, names are separated by whitespace, with each name corresponding to one column. The string above defines three rows:
- Row 1:
headerspans both columns. - Row 2:
sidebarin column 1,mainin column 2. - Row 3:
footerspans both columns.
To span a cell, repeat the name. To leave a cell empty, use a single period . (or a sequence of dots).
Placing Items By Name
Now items use grid-area: <name> to land in their area:
header { grid-area: header; }
aside { grid-area: sidebar; }
main { grid-area: main; }
footer { grid-area: footer; }
Note: grid-area: header (single name) is interpreted as the area name. grid-area: 1 / 1 / 2 / 3 (four numbers) is the line-number shorthand. The parser disambiguates.
Empty Cells With .
If you want a cell to be empty (a gap or padding region), use a period:
grid-template-areas:
"header header header"
". main ."
"footer footer footer";
This creates a layout where the main area is in the center column of the middle row, with empty cells on either side.
Responsive Reflow With Template Swap
The killer feature: in a media query, you redefine the template — completely rearranging the layout in one declaration, without touching the items.
Reading The Visual Sketch
When you align the strings carefully, the template literally looks like the layout you're describing:
grid-template-areas for page-level layouts. Anywhere you'd reach for an ASCII-art comment to explain what's happening, the template IS that comment — and it builds the layout. Code as documentation.Limitations
- Areas must be rectangles. You can't define an L-shaped area. If you try ("a a b" / "a b b"), CSS rejects the template as invalid.
- Names are simple strings. No camelCase enforcement; the parser is permissive. Use kebab-case or single words.
- One template per container. Nested grids each have their own template; they don't inherit.
When To Use Line Numbers Instead
- Highly dynamic placement — items computed in JS that need to land in specific cells based on data. Line numbers are easier to compute.
- Photo galleries with auto-placement — let auto-placement handle it; use
spanto make some items larger. - Layouts that change item count per breakpoint — line numbers compose better with media queries.
For everything page-level — app shells, dashboard frames, marketing pages with a fixed region structure — template-areas wins on readability every time.
Pippa's Note
nav on the left, main in the middle, meta on the right, and a header at the top. The CSS template literally looks like the page. When Dad and I added the quest-evolution-log sidebar, we redefined the template to add an evolution row instead of restructuring all the item placements. The visual readability of template-areas saved an hour of refactoring.