Tools · CSS · Grid-Spielwiese · Anleitungen · The Holy Grail Layout With CSS Grid, and What to Change After
The Holy Grail Layout With CSS Grid, and What to Change After
The holy grail layout is a header across the top, a footer across the bottom, and between them a main column with a sidebar on each side. It got its name because it was hard to build reliably with floats. With CSS Grid it is a three by three grid and five placed items. Grid playground has it as a preset, and the CSS it gives you is a correct starting point. It is not yet a page you would ship, and the gap between the two is the useful part.
From the preset
Pick Holy grail in the playground. It sets three columns, three rows and five items, all custom-placed: item 1 on row 1 spanning all three columns, items 2, 3 and 4 in one cell each on row 2, and item 5 spanning row 3. The copied CSS has a container rule with repeat(3, 1fr) for both columns and rows, plus five item rules of the form grid-column: 1 / span 3; grid-row: 1 / span 1;.
Rename .layout to your page wrapper and the five :nth-child selectors to header, the two sidebars, main and footer, so the rules stay attached to the right element when someone adds a skip link above the header.
What goes wrong: equal rows and equal columns
Paste that CSS into a page and the first thing you notice is a header that is as tall as the main content. When the grid's height is not fixed, 1fr rows all grow to the height of the tallest row, so a one-line header and footer each take a third of the page. The fix is to size the rows by their job: grid-template-rows: auto 1fr auto. Header and footer take only what their content needs, and main takes the rest.
The same logic applies to the columns. Three 1fr columns make each sidebar exactly as wide as the main column. Give the sidebars a fixed width and let main take the rest, and use minmax(0, 1fr) so a wide table or code block in main cannot push the whole layout sideways.
.page {
display: grid;
grid-template-columns: 200px minmax(0, 1fr) 200px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
gap: 16px;
}
.page > header,
.page > footer { grid-column: 1 / -1; }
The 200px is an example, not a rule; use whatever your sidebar content needs. min-height: 100vh keeps the footer at the bottom of the window on a short page. The header and footer rules use 1 / -1, which stays full width even if you later add or remove a column. The three middle items need no placement at all once header and footer are placed: auto-placement drops them into row 2 in source order.
On a phone
Three columns do not fit a narrow screen. A media query that sets grid-template-columns: 1fr stacks everything, but the header and footer rules still say 1 / -1, which is fine, and the sidebars now come in HTML order, which may put a navigation sidebar above the main content. If that is the order you want, you are done. If the aside should come after main, reorder it in the HTML rather than with order, so the reading order matches what is on screen.
The playground cannot show you the media query step, because it builds one grid at a time. Build the wide version there, copy it, and add the single-column version by hand. The playground's numbered rails are still useful for the wide version: when one of the three middle items lands on the wrong row, the rails show which line it actually started on.
The ideas behind tracks, lines and fr are in the background guide, and placing one wide item without disturbing the rest is in the span guide. Or open the playground and start from the Holy grail preset.