CSS grid-template-areas
grid-template-areas lets you name the regions of a layout and draw them as a
map, one quoted string per row. Each child then takes a region with
grid-area: name, so the CSS reads like a picture of the page.
The editor below is a Holy Grail layout built that way. Drag areas around and the map in the CSS tab changes with them. For a blank canvas, use the CSS grid generator on the home page.
Named areas. The CSS is a picture of the layout, and only the properties that actually change get repeated inside each media query.
.holy-grail {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto auto 1fr auto auto;
gap: 16px;
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
}
.holy-grail > .header { grid-area: header; }
.holy-grail > .nav { grid-area: nav; }
.holy-grail > .main { grid-area: main; }
.holy-grail > .aside { grid-area: aside; }
.holy-grail > .footer { grid-area: footer; }
@media (min-width: 900px) {
.holy-grail {
grid-template-columns: 200px 1fr 220px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
}
}
The syntax
Two halves. The container declares the map; each item names the region it fills. The strings are rows, the space-separated words inside them are columns, and repeating a name across neighbouring cells makes that area span them.
.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; } Line the strings up in columns with extra spaces, as above. The browser ignores the whitespace, but the map becomes readable at a glance, and that readability is the reason to use named areas at all.
grid-area: the other half
grid-area on an item takes either a name from the map or four line numbers.
With a name, the item fills that whole region. With numbers, the order is
row-start / column-start / row-end / column-end, rows first, which is the
opposite of the x/y order most people expect.
The two forms mix freely. A grid laid out with named areas can still have one item placed by line numbers, which is how you overlap a badge on a hero image without giving up the map for everything else.
Rules a valid map must follow
When a map breaks any of these rules the browser throws away the whole declaration, not just the bad row, and every item falls back to auto-placement. That is why a single typo can scramble the entire layout.
| Rule | Breaks it | Why |
|---|---|---|
| Every row has the same number of cells | "a a a" "b b" | The map must be a complete rectangle. A short row makes the whole declaration invalid. |
| Each named area is one rectangle | "a b" "b b" | An L-shape or a split area cannot be expressed. Use line numbers for that item instead. |
| Names are CSS identifiers | "1col 2col" | Names cannot start with a digit and are case-sensitive: Main and main are different areas. |
| Empty cells are dots | "a _ a" | A dot (or a run of dots with no spaces, such as ...) is an empty cell. Any other character is a name. |
| Areas cannot overlap | — | Each cell holds exactly one name, so the map cannot describe overlap. Stack items with grid-area line numbers. |
Responsive layouts: redraw the map
This is where named areas pay off. The HTML stays the same and each item keeps its
grid-area. At each breakpoint you redeclare the map, and the page
rearranges.
.page {
display: grid;
grid-template-columns: 1fr;
grid-template-areas:
"header"
"nav"
"main"
"footer";
}
@media (min-width: 768px) {
.page {
grid-template-columns: 200px 1fr;
grid-template-areas:
"header header"
"nav main"
"footer footer";
}
} Writing those media queries by hand is the tedious part, and it is exactly what the responsive grid generator automates: draw the layout at each width and it repeats only the properties that change. Keep an eye on source order when the map rearranges. Keyboard and screen-reader users follow the HTML, not the picture.
The grid-template shorthand
grid-template sets the map, the row sizes and the column sizes in one
declaration. Each row string is followed by its height, and the column list comes after a
slash.
.page {
display: grid;
grid-template:
"header header" auto
"nav main" 1fr
"footer footer" auto
/ 200px 1fr;
} It is compact, but harder to override in a media query because it resets all three properties at once. Most codebases, and this generator, write the longhands.
Named areas create named lines
Every area called main also gives you lines called main-start
and main-end on both axes. You can place other items against them, so a
full-width banner can line up with the content column without hard-coding numbers.
/* Naming "main" also creates the lines
main-start and main-end in both directions. */
.banner {
grid-column: main-start / main-end;
grid-row: 1;
} When not to use named areas
- Overlapping items. The map cannot describe overlap. Use line numbers for the items that overlap.
- Repeating content. A card grid of unknown length wants
repeat(auto-fill, minmax(240px, 1fr))and auto-placement, not a named cell per card. grid-template-columns covers how that works. - Very dense grids. A twelve-column map with dozens of names stops being readable, which defeats the purpose.
The generator makes that choice for you: it exports named areas where the layout tiles cleanly and falls back to line numbers where it cannot, with a note explaining why. The CSS Grid cheat sheet lists every related property, and the CSS Grid visualizer will draw a map you already have so you can see what it does.
Layouts built with grid-template-areas
Frequently asked questions
What does grid-template-areas do?
grid-template-areas names the regions of a grid by drawing them as a map, one quoted string per row. Items are then placed into a region with grid-area: name. The browser works out the row and column lines from the map, so you never write line numbers.What is the difference between grid-area and grid-template-areas?
grid-template-areas goes on the container and defines the named regions; grid-area goes on an item and says which region it occupies. grid-area also accepts four line numbers instead of a name, as row-start / column-start / row-end / column-end.Why is my grid-template-areas not working?
grid-template-areas entirely instead of fixing part of it. Check that every row has the same number of cells, every name forms a single rectangle, and no name starts with a digit. The other usual cause is a grid-area name that does not match the map exactly, since names are case-sensitive.How do I leave a cell empty in grid-template-areas?
"header header" ". main". A run of dots with no spaces between them, such as ..., still counts as one empty cell, which is useful for lining the map up in columns.Can grid areas overlap?
grid-template-areas, because each cell of the map holds one name. To overlap two items, place one or both with line numbers, for example grid-area: 1 / 1 / 3 / 3. Items can share cells that way even when the rest of the grid uses named areas.How do I make grid-template-areas responsive?
grid-template-areas (and the column tracks) inside a media query. The items keep their grid-area names, so rearranging the whole page at a breakpoint is only a new map. The generator on this page writes those media queries for you.