ποΈ Holy Grail Layout
The most classic web layout pattern: a full-height page with a header, three-column content area (navigation, main content, aside), and a footer. Once notoriously complex β with CSS Grid it takes 15 lines.
1. Basic Holy Grail
The core structure: header spans full width, three columns fill remaining height with 1fr, footer spans full width. The grid-template shorthand defines rows and areas together.
.page { display: grid; min-height: 100vh; grid-template: "header header header" auto "nav main aside" 1fr "footer footer footer" auto / 200px 1fr 180px; gap: 0; /* or use gap for spacing */ } .header { grid-area: header; } .nav { grid-area: nav; } .main { grid-area: main; } .aside { grid-area: aside; } .footer { grid-area: footer; }
2. Verbose Version (for Clarity)
The same layout written with separate properties. This is more readable when learning β once you understand it, use the shorthand.
.page { display: grid; min-height: 100vh; grid-template-columns: 200px 1fr 180px; grid-template-rows: auto 1fr auto; grid-template-areas: "header header header" "nav main aside" "footer footer footer"; } /* Each child just assigns itself to an area */ .header { grid-area: header; } .nav { grid-area: nav; } .main { grid-area: main; } .aside { grid-area: aside; } .footer { grid-area: footer; }
3. Responsive Holy Grail
On mobile, redefine the areas to stack everything vertically. The header stays, sidebar collapses below main, footer stays at the bottom.
.page { display: grid; grid-template-columns: 200px 1fr 180px; grid-template-rows: auto 1fr auto; grid-template-areas: "header header header" "nav main aside" "footer footer footer"; min-height: 100vh; } @media (max-width: 768px) { .page { grid-template-columns: 1fr; grid-template-rows: auto; grid-template-areas: "header" "main" "nav" "aside" "footer"; } }
4. Variant: Sticky Header & Scrollable Main
A common app pattern where the header is sticky, the main area scrolls, and the footer sticks to the bottom. Uses height: 100vh on the grid container and overflow: auto on main.
.app { display: grid; height: 100vh; /* not min-height! */ grid-template-columns: 200px 1fr; grid-template-rows: 60px 1fr 40px; grid-template-areas: "header header" "nav main" "footer footer"; } .header { grid-area: header; position: sticky; top: 0; z-index: 10; } .main { grid-area: main; overflow-y: auto; /* scrollable! */ }