Grid template areas let you name regions of the grid and assign items to them using plain ASCII art-like strings. Instead of managing line numbers for every item, you draw the layout visually in your CSS. This makes complex page layouts dramatically more readable and maintainable โ changing the layout is as simple as redrawing the ASCII diagram. In this lesson you will build full-page layouts using named grid areas and learn to update them at breakpoints.
grid-template-areas Syntax
| Concept | Syntax | Rules |
|---|---|---|
| Define named areas | grid-template-areas: "header header" "sidebar main" "footer footer" |
Each string is a row; each word is a cell; areas must be rectangular |
| Assign item to area | grid-area: header |
Item fills the entire named region |
| Empty cell | . (dot) |
Leaves that cell empty โ no item placed there |
| Spanning | Repeat the area name across multiple cells | Repeated names form a rectangular region |
Combining template-areas with template-columns
| Property | Controls | Example |
|---|---|---|
grid-template-areas |
Which cells belong to which named area | "sidebar main" |
grid-template-columns |
How wide each column is | 240px 1fr |
grid-template-rows |
How tall each row is | 64px 1fr 48px |
| All three together | Complete explicit grid definition | Named, sized, and structured layout |
Responsive Layout Patterns with grid-template-areas
| Screen Size | Areas String | Column Definition |
|---|---|---|
| Mobile (stacked) | "header" "main" "sidebar" "footer" |
1fr (single column) |
| Tablet (2 col) | "header header" "main sidebar" "footer footer" |
2fr 1fr |
| Desktop (3 col) | "header header header" "nav main sidebar" "footer footer footer" |
200px 1fr 200px |
grid-template-areas, grid-template-columns, and grid-template-rows. The HTML and grid-area assignments on items stay exactly the same โ the layout rearranges itself. This is one of Grid’s biggest maintenance advantages over Flexbox for page-level layouts..) for empty cells is a convention, but multiple dots (...) also work and can make the visual alignment clearer in your code.Basic Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Grid Template Areas</title>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; min-height: 100vh; background: #f1f5f9; }
/* โโ Full page layout with named areas โโ */
.page-layout {
display: grid;
min-height: 100vh;
/* Mobile first: single column stack */
grid-template-columns: 1fr;
grid-template-rows: auto auto 1fr auto auto;
grid-template-areas:
"header"
"nav"
"main"
"sidebar"
"footer";
}
/* Tablet: header+footer full-width, sidebar moves right */
@media (min-width: 640px) {
.page-layout {
grid-template-columns: 1fr 240px;
grid-template-rows: 60px 1fr 56px;
grid-template-areas:
"header header"
"main sidebar"
"footer footer";
}
}
/* Desktop: add left nav column */
@media (min-width: 1024px) {
.page-layout {
grid-template-columns: 200px 1fr 260px;
grid-template-rows: 60px 1fr 56px;
grid-template-areas:
"header header header"
"nav main sidebar"
"footer footer footer";
}
}
/* Area assignments */
.site-header { grid-area: header; }
.site-nav { grid-area: nav; }
.site-main { grid-area: main; }
.site-sidebar { grid-area: sidebar; }
.site-footer { grid-area: footer; }
/* Visual styling */
.site-header {
background: #1e293b; color: white;
display: flex; align-items: center; justify-content: space-between;
padding: 0 24px; font-weight: 700; font-size: 1rem;
}
.site-nav {
background: #f8fafc; border-right: 1px solid #e2e8f0;
padding: 20px 0; overflow-y: auto;
}
.nav-link {
display: block; padding: 10px 20px;
color: #475569; text-decoration: none; font-size: 0.875rem;
}
.nav-link:hover { background: #ede9fe; color: #4f46e5; }
.nav-link.active { color: #4f46e5; font-weight: 600; border-left: 3px solid #4f46e5; }
.site-main {
padding: 32px; overflow-y: auto; background: white;
}
.site-main h1 { font-size: 1.5rem; margin-bottom: 16px; color: #0f172a; }
.site-main p { color: #64748b; line-height: 1.7; font-size: 0.95rem; margin-bottom: 12px; }
.site-sidebar {
background: #f8fafc; border-left: 1px solid #e2e8f0;
padding: 24px 20px; overflow-y: auto;
}
.widget-title { font-size: 0.8rem; font-weight: 700; text-transform: uppercase;
letter-spacing: 0.06em; color: #64748b; margin-bottom: 12px; }
.site-footer {
background: #1e293b; color: #94a3b8;
display: flex; align-items: center; justify-content: space-between;
padding: 0 24px; font-size: 0.8rem;
}
</style>
</head>
<body>
<div class="page-layout">
<header class="site-header">
<span>MyApp</span>
<span style="font-size:0.8rem;font-weight:400;opacity:.7">grid-template-areas layout</span>
</header>
<nav class="site-nav">
<a href="#" class="nav-link active">Dashboard</a>
<a href="#" class="nav-link">Analytics</a>
<a href="#" class="nav-link">Projects</a>
<a href="#" class="nav-link">Team</a>
<a href="#" class="nav-link">Settings</a>
</nav>
<main class="site-main">
<h1>Grid Template Areas</h1>
<p>This page is laid out using <code>grid-template-areas</code>. On mobile it stacks into a single column. On tablet, the sidebar moves to the right. On desktop, the left nav column appears.</p>
<p>Resize the window to see the layout adapt. The HTML structure never changes โ only the CSS template-areas definition at each breakpoint.</p>
</main>
<aside class="site-sidebar">
<p class="widget-title">Recent Activity</p>
<p style="font-size:0.85rem;color:#64748b;line-height:1.6">Project Alpha updated<br>Team meeting scheduled<br>Report exported</p>
</aside>
<footer class="site-footer">
<span>© 2025 MyApp</span>
<span>CSS Grid Layout Demo</span>
</footer>
</div>
</body>
</html>
How It Works
Step 1 โ Areas Define the ASCII Blueprint
Each string in grid-template-areas represents a row. Words within each string represent cells. Identical adjacent words form a named area. The layout is self-documenting โ reading the areas string tells you exactly what the layout looks like.
Step 2 โ Items Self-Assign with grid-area
Each semantic element gets a single grid-area: name declaration. The element expands to fill every cell in that named region โ spanning multiple columns and rows as defined by the template. No line numbers needed.
Step 3 โ Responsive Redesign Updates Only the Template
At the tablet breakpoint, the areas string changes from a 1-column stack to a 2-column layout with sidebar on the right. The HTML is untouched โ the elements reposition themselves automatically by reading the new template. This is the holy grail of responsive layout: changing layout without touching markup.
Step 4 โ Desktop Adds a Third Column
At 1024px, the template expands to three columns by adding “nav” to row 2. The grid-template-columns changes to 200px 1fr 260px โ fixed left nav, fluid main, fixed right sidebar. The header and footer each use their name three times, spanning all three columns.
Step 5 โ Dots Create Empty Cells
A . (dot) in the areas string leaves that cell empty โ no item is placed there, and the grid maintains the track dimensions. This is useful for asymmetric designs where you want whitespace in specific cells without adding dummy HTML elements.
Real-World Example: Magazine Article Layout
/* magazine.css */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: Georgia, serif; background: #fffbf7; color: #1c1917; }
.article-grid {
display: grid;
max-width: 1000px;
margin: 0 auto;
padding: 40px 24px;
gap: 24px;
grid-template-columns: 1fr;
grid-template-areas:
"kicker"
"headline"
"byline"
"hero"
"body"
"pullquote"
"related";
}
@media (min-width: 768px) {
.article-grid {
grid-template-columns: 2fr 1fr;
grid-template-rows: auto auto auto auto auto;
grid-template-areas:
"kicker kicker"
"headline headline"
"byline byline"
"hero hero"
"body related"
"pullquote related";
}
}
.art-kicker { grid-area: kicker; }
.art-headline { grid-area: headline; }
.art-byline { grid-area: byline; }
.art-hero { grid-area: hero; }
.art-body { grid-area: body; }
.art-pullquote { grid-area: pullquote; }
.art-related { grid-area: related; }
.art-kicker {
font-family: system-ui, sans-serif;
font-size: 0.7rem; font-weight: 800;
text-transform: uppercase; letter-spacing: 0.1em;
color: #dc2626;
}
.art-headline { font-size: clamp(1.8rem, 5vw, 3rem); line-height: 1.1; }
.art-byline {
font-family: system-ui, sans-serif; font-size: 0.85rem;
color: #78716c; border-top: 1px solid #e7e5e4;
border-bottom: 1px solid #e7e5e4; padding: 10px 0;
}
.art-hero {
height: 320px; border-radius: 12px; overflow: hidden;
background: linear-gradient(135deg, #4f46e5, #0891b2);
}
.art-body p { line-height: 1.85; margin-bottom: 18px; font-size: 1.05rem; }
.art-pullquote {
border-left: 5px solid #dc2626; padding: 16px 20px;
font-size: 1.25rem; font-style: italic; color: #44403c;
background: #fef9c3;
}
.art-related {
background: #f5f5f4; border-radius: 10px; padding: 20px;
font-family: system-ui, sans-serif;
}
Common Mistakes
Mistake 1 โ Non-rectangular area name
โ Wrong โ L-shaped area is invalid; browser ignores the template:
grid-template-areas:
"main main sidebar"
"main footer footer"; /* "main" is L-shaped โ INVALID */
โ Correct โ all area names must form rectangles:
grid-template-areas:
"main sidebar"
"main footer"; /* "main" is a 1x2 rectangle โ valid */
Mistake 2 โ Mismatched area name in grid-area vs template
โ Wrong โ typo means the item is auto-placed instead of named-placed:
grid-template-areas: "header header";
.site-header { grid-area: heder; } /* typo โ item auto-placed */
โ Correct โ names must match exactly (case-sensitive):
.site-header { grid-area: header; }
Mistake 3 โ Forgetting to update column definition at breakpoints
โ Wrong โ changing areas without changing column counts leaves a broken layout:
@media (min-width: 768px) {
.layout {
grid-template-areas: "nav main sidebar"; /* 3 columns defined... */
/* grid-template-columns not updated โ still 1fr (single column) */
}
}
โ Correct โ always update both areas and columns together:
@media (min-width: 768px) {
.layout {
grid-template-columns: 200px 1fr 240px;
grid-template-areas: "nav main sidebar";
}
}
Quick Reference
| Concept | Syntax | Notes |
|---|---|---|
| Define areas | grid-template-areas: "h h" "n m" "f f" |
Each string = a row; words = cells |
| Assign item | grid-area: header |
Fills entire named region |
| Empty cell | . or ... |
Dot(s) leave cell empty |
| Spanning | Repeat name across cells | Must form a rectangle |
| Responsive swap | Redefine areas in media query | HTML unchanged โ layout rearranges |
| Column widths | grid-template-columns |
Must match number of area columns |