Line numbers work, but grid-column: 2 / 4 does not tell you much when you read it later. Grid lets you name areas and lines instead, and grid-template-areas lets you draw the layout as a small text map right in your CSS.
Template areas
Start with semantic HTML:
<div class="page">
<header class="page-header">Header</header>
<nav class="page-nav">Navigation</nav>
<main class="page-main">Main content</main>
<aside class="page-aside">Related</aside>
<footer class="page-footer">Footer</footer>
</div>
Give each item a name with grid-area, then arrange the names on the container:
.page-header { grid-area: header; }
.page-nav { grid-area: nav; }
.page-main { grid-area: main; }
.page-aside { grid-area: aside; }
.page-footer { grid-area: footer; }
.page {
display: grid;
grid-template-columns: 14rem 1fr 16rem;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
gap: 1.5rem;
min-height: 100vh;
}
Each quoted string is one row. Each word is one column. Repeating a name across cells makes that area span them. The layout reads like a picture of the page.
The extra spaces inside the strings are only for alignment. You can use as many as you like.
Empty cells
A full stop marks a cell that belongs to no area:
.dashboard {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-areas:
"stats stats ."
"chart chart list";
}
You can also use several full stops together, such as ..., to keep columns aligned in your text.
The rules for areas
Template areas are strict. A single mistake makes the whole grid-template-areas declaration invalid, and the browser ignores it.
- Every row must have the same number of cells. Three words in one row and two in another is invalid.
- Areas must be rectangles. An L-shape or a T-shape is not allowed.
- An area's cells must be connected. You cannot use the same name in two separate places.
/* Invalid: "main" makes an L-shape */
.broken {
grid-template-areas:
"header header"
"main aside"
"main main";
}
If your layout suddenly collapses into a single column, check the Styles pane in DevTools. An invalid grid-template-areas value is shown crossed out with a warning icon. Then count the cells in each row.
Rearranging the layout at different widths
Because the layout lives in one declaration, changing it for different screen sizes is easy. Write the small-screen layout first, then enhance it when there is more room:
.page {
display: grid;
gap: 1rem;
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
}
@media (min-width: 48rem) {
.page {
grid-template-columns: 14rem 1fr;
grid-template-areas:
"header header"
"nav main"
"aside main"
"footer footer";
}
}
@media (min-width: 72rem) {
.page {
grid-template-columns: 14rem 1fr 16rem;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
}
}
The @media (min-width: ...) blocks apply only when the viewport is at least that wide. The items keep their grid-area names; only the map changes. Media query syntax, range syntax and choosing breakpoints are covered properly in the Responsive Web Design course.
Template areas make it tempting to move content around freely, for example putting the sidebar visually above the main content on mobile. Remember that keyboard and screen reader users follow the HTML order. Rearrange for visual balance, not to change the reading order, and keep the HTML in the order that makes sense.
The grid-template shorthand
grid-template can set rows, columns and areas in one go, with each row's size after its string:
.page {
display: grid;
grid-template:
"header header" auto
"nav main" 1fr
"footer footer" auto
/ 14rem 1fr;
}
The column sizes come after the slash. It is compact, but harder to read for beginners. Separate properties are perfectly fine.
Named lines
Instead of naming areas, you can name the lines between tracks. Put names in square brackets in the track list:
.layout {
display: grid;
grid-template-columns:
[full-start] 1fr
[content-start] minmax(0, 60rem) [content-end]
1fr [full-end];
}
.layout > * {
grid-column: content;
}
.layout > .full-bleed {
grid-column: full;
}
This is a popular pattern for article layouts. Normal content sits in a centred column up to 60rem wide. Elements with .full-bleed, such as large images, stretch edge to edge.
How does grid-column: content work? When lines are named something-start and something-end, Grid automatically creates an implicit area called something. So content means "from content-start to content-end".
A line can have several names, as in [sidebar-end main-start], and you can place items with names and spans:
.note {
grid-column: content-start / span 1;
}
Areas create named lines too
It works the other way as well. An area called main creates lines called main-start and main-end, so you can line up something with an area's edges:
.overlay {
grid-column: main-start / aside-end;
grid-row: main;
}
Choosing between line numbers, names and areas
| Technique | Best for |
|---|---|
Line numbers and span | Small, simple grids; galleries |
| Template areas | Page layouts and components with a few named regions |
| Named lines | Repeating patterns such as content and full-bleed columns |
Areas are the most readable, but each named item can appear only once. For a grid of repeated items, such as cards, you do not name areas at all; auto-placement is simpler.
Seeing areas in DevTools
Turn on the grid overlay (click the grid badge in the Elements panel). In the Layout pane, enable Show area names and Show line names. The overlay labels each area on the page, which is the quickest way to confirm the browser read your map the way you intended.
Summary
grid-areanames an item;grid-template-areasarranges the names in rows of strings.- Each row needs the same number of cells, areas must be rectangles, and
.marks an empty cell. - An invalid area map is ignored completely; check DevTools for a crossed-out declaration.
- Redefine
grid-template-areasinside media queries to rearrange a layout, keeping a logical HTML order. - Named lines such as
[content-start]and[content-end]create an implicit area you can place items into.