cssgridgenerator All tools
Property guide

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.

Open in
1080px

Drag across the grid to draw an area. Arrow keys nudge, Shift + arrows resize.

space to pan · ⌘scroll to zoom
1200px21fr3220px4
1auto21fr3auto4
header1 / 1 / 2 / 4
nav2 / 1 / 3 / 2
main2 / 2 / 3 / 3
aside2 / 3 / 3 / 4
footer3 / 1 / 4 / 4

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

Browse all layout patterns →

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?
Most often the map is invalid, and the browser drops an invalid 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?
Put a dot in that cell: "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?
Not through 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?
Redeclare 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.
What happens if an item uses an area name that is not in the map?
Nothing errors. The browser places the item in the implicit grid, outside the tracks you defined, which usually shows up as an unexpected extra row or column. It is almost always a typo in the name.