Grid Template Areas

โ–ถ Try It Yourself

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
Note: Named grid areas must form a rectangle โ€” you cannot create an L-shaped or irregular area by repeating a name in a non-rectangular pattern. The browser will ignore the template entirely if an area name appears in a non-rectangular shape and fall back to auto-placement.
Tip: You can change an entire page layout at a breakpoint by simply redefining 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.
Warning: Grid area names are case-sensitive and must be valid CSS identifiers โ€” no spaces, no special characters other than hyphens and underscores. Using a dot (.) 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>&copy; 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";
  }
}

▶ Try It Yourself

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

🧠 Test Yourself

Which grid-template-areas value is INVALID and will be ignored by the browser?





โ–ถ Try It Yourself