Home / Snippets / Layout & Grid /

Holy grail layout

The classic five-region page layout (header, nav sidebar, main content, aside sidebar, footer) using CSS Grid.

Header
Nav
Main content
Aside
Widely supported
layoutgrid

Quick implementation

.holy-grail {
  display: grid;
  grid-template-areas:
    "header  header  header"
    "nav     main    aside"
    "footer  footer  footer";
  grid-template-columns: 12rem 1fr 12rem;
  grid-template-rows: auto 1fr auto;
  min-height: 100dvh;
  gap: 0;
}

.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; }

/* Stack on narrow screens */
@media (max-width: 48rem) {
  .holy-grail {
    grid-template-areas:
      "header"
      "nav"
      "main"
      "aside"
      "footer";
    grid-template-columns: 1fr;
  }
}

Prompt this to your LLM

Paste this into ChatGPT, Claude, or any code-generating model to scaffold the pattern instantly.

Build a "holy grail" page layout using CSS Grid. The
container should have grid-template-areas with three rows:
"header header header", "nav main aside", and
"footer footer footer". Set grid-template-columns to
12rem 1fr 12rem and grid-template-rows to auto 1fr auto.
Give it min-height: 100dvh. Assign grid-area to each
direct child: header, nav, main, aside, footer. Add a
media query at max-width: 48rem that collapses everything
into a single column by redefining grid-template-areas
and setting grid-template-columns: 1fr.

Why this matters

The holy grail layout was notoriously difficult before CSS Grid, requiring floats, clearfixes, and equal-height column hacks. With grid-template-areas, the entire layout is expressed in a readable ASCII-art grid map. Changing the layout for different screen sizes is as simple as rewriting the area strings in a media query. This is the foundational layout for dashboards, documentation sites, and content-heavy applications.

The logic

The grid-template-areas property defines named regions in a visual grid map. Each row is a quoted string, and repeated names span multiple columns. The header and footer each span all three columns. The middle row has nav, main, and aside side by side. grid-template-columns: 12rem 1fr 12rem gives fixed-width sidebars and a fluid center. grid-template-rows: auto 1fr auto makes the header and footer size to their content while the middle row takes all remaining vertical space, achieving a full-height layout with min-height: 100dvh.

Accessibility & performance

Use proper semantic elements: <header>, <nav>, <main>, <aside>, and <footer>. These give screen readers a navigable landmark structure automatically. Grid reordering (changing area assignments) changes only the visual order, not the DOM order, so keep the source order logical for keyboard and screen-reader users. The grid layout is computed once by the browser on render and does not trigger expensive reflows during scroll. Using 100dvh instead of 100vh avoids the mobile address-bar height issue.