The "Holy Grail" layout is one of the oldest naming conventions in web design: a header across the top, a footer across the bottom, and three columns in between: navigation on the left, main content in the middle, and a sidebar on the right. It used to require floats, negative margins and a fair amount of hackery. CSS Grid makes it about ten lines of code.

header
nav
main
aside

1. Set up the grid areas

The cleanest way to build this layout is with named grid-template-areas. You lay the page out visually in your CSS, which makes the structure obvious to anyone reading the file later.

.layout {
  display: grid;
  grid-template-areas:
    "header header header"
    "nav    main   aside"
    "footer footer footer";
  grid-template-columns: 200px 1fr 220px;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
  gap: 16px;
}

.header { grid-area: header; }
.nav    { grid-area: nav; }
.main   { grid-area: main; }
.aside  { grid-area: aside; }
.footer { grid-area: footer; }

2. Match your HTML to the areas

<div class="layout">
  <header class="header">Site header</header>
  <nav class="nav">Navigation</nav>
  <main class="main">Main content</main>
  <aside class="aside">Sidebar</aside>
  <footer class="footer">Site footer</footer>
</div>

Each element's grid-area name has to match a name used in grid-template-areas exactly, including case. This is the single most common typo in Holy Grail layouts: a mismatched name will silently drop the element into the default flow instead of its area, and Grid Detective is built to catch exactly that.

3. Make it responsive

Below a certain width, three columns stop making sense. Redefine the areas in a single column and let the grid columns collapse to 1fr:

@media (max-width: 700px) {
  .layout {
    grid-template-areas:
      "header"
      "nav"
      "main"
      "aside"
      "footer";
    grid-template-columns: 1fr;
  }
}

Because every child is already positioned by name, you do not need to reorder any HTML, only the area map changes.

The same layout in Tailwind

If you are working in Tailwind, the equivalent uses grid-cols-[200px_1fr_220px] with arbitrary values, plus a couple of col-start / row-start utilities for the header and footer to span the full width:

<div class="grid grid-cols-[200px_1fr_220px] grid-rows-[auto_1fr_auto] gap-4 min-h-screen">
  <header class="col-span-3">Site header</header>
  <nav>Navigation</nav>
  <main>Main content</main>
  <aside>Sidebar</aside>
  <footer class="col-span-3">Site footer</footer>
</div>
Tip: if the sidebar's content is genuinely optional (an ad, a "related posts" widget), consider making it a fourth grid-template-areas column only on wide screens, rather than forcing it into the layout on mobile where it usually just adds scroll length.

Common pitfalls

  • Mismatched area names between grid-template-areas and each child's grid-area.
  • Forgetting min-height: 100vh on the layout, which leaves the footer floating mid-page on short content.
  • Fixed pixel widths on nav/aside with no fallback for narrow viewports: use the responsive rewrite above rather than trying to squeeze three columns onto a phone.

You can paste any version of this layout straight into the CSS Grid Generator to preview it live, or into Grid Detective if something is not lining up the way you expect.