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.
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>
Common pitfalls
- Mismatched area names between
grid-template-areasand each child'sgrid-area. - Forgetting
min-height: 100vhon 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.