What Is grid-template-areas?
CSS Grid's grid-template-areas property is one of the most visually intuitive features in all of CSS. Instead of placing grid items with abstract line numbers, you draw your layout as an ASCII art diagram directly in your CSS. The browser reads this diagram and positions your elements accordingly.
This property is perfect for high-level page structure — the kind of layout you might sketch on a whiteboard. Think headers, sidebars, main content areas, and footers. With grid-template-areas, what you type in your CSS literally looks like what you see in the browser.
Basic Syntax
Each string in the property value represents one row of the grid. Each word within a string represents one cell, and cells with the same name form a single named area.
.container {
display: grid;
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
grid-template-columns: 240px 1fr 1fr;
grid-template-rows: 80px 1fr 60px;
}
This defines a three-column, three-row grid. The header area spans all three columns in the first row. The sidebar occupies the first column of the second row, while main spans the second and third columns. The footer spans all three columns in the last row.
The grid-area Property on Children
Naming areas in grid-template-areas is only half the work. You must also assign each child element to its named area using the grid-area property.
header { grid-area: header; }
aside { grid-area: sidebar; }
main { grid-area: main; }
footer { grid-area: footer; }
The value of grid-area must exactly match a name defined in grid-template-areas. Names are case-sensitive. The order of elements in your HTML does not affect placement — CSS Grid positions them purely by their grid-area assignment, which is a powerful advantage for accessibility and SEO (content order in HTML can differ from visual order).
Complete Full-Page Layout Example
Here is a complete, working example of the classic header–sidebar–main–footer layout often called the "Holy Grail" layout:
/* HTML Structure */
<div class="page">
<header>Site Header</header>
<nav>Sidebar Nav</nav>
<main>Main Content</main>
<aside>Right Panel</aside>
<footer>Site Footer</footer>
</div>
/* CSS */
.page {
display: grid;
min-height: 100vh;
grid-template-columns: 220px 1fr 200px;
grid-template-rows: 70px 1fr 60px;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
}
header { grid-area: header; background: #1e293b; color: #fff; }
nav { grid-area: nav; background: #f1f5f9; }
main { grid-area: main; padding: 24px; }
aside { grid-area: aside; background: #f8fafc; }
footer { grid-area: footer; background: #1e293b; color: #fff; }
You can paste this directly into the Live HTML/CSS Editor to see it rendered instantly. Notice how the CSS reads like a wireframe — anyone on your team can understand the layout at a glance, even without deep CSS knowledge.
The Dot Syntax for Empty Cells
Sometimes you want a cell in your grid to remain empty — no element should occupy it. Use a period (.) as a placeholder for an empty cell.
.layout {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-areas:
"logo . nav"
"hero hero hero"
"foot foot foot";
}
The period in "logo . nav" creates an empty cell between the logo and the navigation. You can use multiple consecutive periods (...) for clarity — the browser treats any number of consecutive dots as a single empty cell.
Rules for Named Areas
There are important constraints on how you define grid areas:
- Rectangular only: Every named area must form a rectangle. L-shapes, T-shapes, and other non-rectangular configurations are invalid and will cause the entire
grid-template-areasvalue to be ignored. - No gaps within a name: If you write
"a . a", the twoacells are not connected — they are two separate areas with the same name, which is invalid. - Consistent column count: Every row string must have the same number of cells. Inconsistent counts will also invalidate the entire declaration.
- Valid identifiers: Area names follow CSS custom identifier rules. They cannot start with a number and cannot be CSS keywords like
noneorauto.
Named Lines Are Created Automatically
A powerful hidden benefit of grid-template-areas is that it automatically creates named grid lines. For each area named foo, the browser implicitly creates lines named foo-start and foo-end on all four sides of that area.
.container {
grid-template-areas:
"header header"
"sidebar main";
}
/* You can now use these implicit named lines: */
.some-element {
grid-column: sidebar-start / main-end;
grid-row: header-end / main-end;
}
This bidirectional relationship between grid-template-areas and named lines gives you two complementary ways to describe and reference your grid structure.
Responsive Template Areas with Media Queries
One of the best use cases for grid-template-areas is creating responsive layouts by simply redefining the area map at different breakpoints. The visual nature of the property makes the before-and-after immediately obvious.
/* Desktop: three-column layout */
.page {
display: grid;
grid-template-columns: 240px 1fr 200px;
grid-template-rows: 70px 1fr 60px;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
min-height: 100vh;
}
/* Tablet: two-column, sidebar collapses right panel */
@media (max-width: 1024px) {
.page {
grid-template-columns: 220px 1fr;
grid-template-areas:
"header header"
"nav main"
"footer footer";
}
aside { display: none; }
}
/* Mobile: single-column stack */
@media (max-width: 640px) {
.page {
grid-template-columns: 1fr;
grid-template-rows: auto;
grid-template-areas:
"header"
"main"
"nav"
"footer";
}
}
Notice how on mobile, the nav (sidebar) is moved below main. This way, the main content appears first for mobile users — a critical consideration for UX and SEO — while the desktop layout keeps the sidebar on the left. The HTML order does not change, only the visual order does. Use the CSS Formatter to keep your media query blocks clean and readable.
Dashboard Layout Example
.dashboard {
display: grid;
height: 100vh;
grid-template-columns: 260px 1fr;
grid-template-rows: 64px 1fr 50px;
grid-template-areas:
"sidebar topbar"
"sidebar content"
"sidebar statusbar";
}
.sidebar { grid-area: sidebar; overflow-y: auto; }
.topbar { grid-area: topbar; }
.content { grid-area: content; overflow-y: auto; padding: 20px; }
.statusbar { grid-area: statusbar; }
This dashboard keeps the sidebar spanning the full height while the right side has a topbar, scrollable content area, and a status bar at the bottom. The grid-template-areas map makes this relationship completely explicit.
Combining with grid-template Shorthand
The grid-template shorthand combines grid-template-rows, grid-template-columns, and grid-template-areas in one declaration:
.page {
display: grid;
grid-template:
"header header" 70px
"nav main" 1fr
"footer footer" 60px
/ 240px 1fr;
}
Each row is written as "area-names" row-height, and the column sizes follow a slash at the end. This is very compact but can be harder to read in complex layouts. Use it when brevity matters, and the expanded form when readability is the priority.
Best Practices
- Use
grid-template-areasfor page-level layouts (header, nav, main, footer). For component-level grids with many similar items (card grids, galleries), userepeat()andauto-fill/auto-fitinstead. - Keep names semantic: Use
header,sidebar,main,footerrather than abstract names likea,b,c. - Always pair
grid-template-areaswith explicitgrid-template-columnsandgrid-template-rowsto avoid relying on implicit track sizing. - When reordering areas in media queries for accessibility, ensure the logical reading order is maintained in the HTML.