CSS Grid Fundamentals
Two-dimensional layout with tracks, gaps, placement, fr units, and when grid beats flex for page scaffolding.
- css
- css-grid
- layout
- grid
CSS Grid is a two-dimensional layout system: you define rows and columns, then place items into cells or areas. Flexbox is one-dimensional. Page shells, card matrices, dashboards, and form layouts that need alignment on both axes are grid problems.
Docs: MDN CSS Grid, web.dev Learn CSS — Grid, CSS Grid Layout Module.
Container vs items
.dashboard {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
gap: 1rem;
min-height: 100vh;
}
- Grid container —
display: gridorinline-grid - Grid items — in-flow children
- Tracks — rows and columns
- Gaps — gutters between tracks (
gap,row-gap,column-gap) - Cells / areas — intersections of tracks where items live
Only direct children are grid items. Nested UI needs its own grid or flex context.
Defining tracks
/* Fixed + flexible */
.cols {
display: grid;
grid-template-columns: 200px 1fr 2fr;
}
/* Repeat helper */
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
/* Responsive without breakpoints (often) */
.auto {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1rem;
}
| Unit / function | Meaning |
|---|---|
px / rem |
Fixed track size |
% |
Share of grid container’s size |
fr |
Fraction of free space after fixed tracks |
minmax(min, max) |
Track clamps between min and max |
auto |
Size to content (with max constraints from the algorithm) |
repeat(n, …) |
Repeat a track list |
1fr 1fr is two equal free-space shares — not always equal to “50% 50%” once gaps and min-content sizes enter. When a track’s content has a large minimum size, fr tracks can refuse to shrink the way beginners expect. Same family of bug as flex: use minmax(0, 1fr) when you need true equal flexible tracks that can shrink below content size.
.equal-and-shrinkable {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
Placing items
Default: items auto-place in order, one cell each, row by row (grid-auto-flow: row).
.header {
grid-column: 1 / -1; /* full width: line 1 to last */
}
.sidebar {
grid-column: 1;
grid-row: 2 / 4;
}
.main {
grid-column: 2;
grid-row: 2;
}
Line numbers start at 1. Negative lines count from the end (-1 is the last line). Spans:
.feature {
grid-column: span 2;
grid-row: span 2;
}
Named areas
.page {
display: grid;
grid-template-columns: 12rem 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"nav nav"
"side main"
"foot foot";
gap: 1rem;
}
.page__nav { grid-area: nav; }
.page__side { grid-area: side; }
.page__main { grid-area: main; }
.page__foot { grid-area: foot; }
Areas must form rectangles. For multi-column responsive shells, redefine grid-template-areas in a media query — clearer than rewriting line numbers.
Alignment
Grid has two levels: tracks in the container and content inside a cell.
.grid {
display: grid;
place-items: start stretch; /* align-items + justify-items */
place-content: center; /* when grid is smaller than container */
}
.item {
justify-self: end;
align-self: center;
}
| Property | Controls |
|---|---|
justify-items / align-items |
Default alignment of items in their cells |
justify-self / align-self |
Per-item override |
justify-content / align-content |
Packing of the whole grid when tracks don’t fill the container |
stretch is the default for items — full cell. For card titles that should top-align while neighbors stretch, set align-items: start on the grid or align-self on items.
Implicit tracks and auto-flow
If you place something outside explicit tracks, or have more items than cells, the grid creates implicit tracks:
.feed {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(8rem, auto);
grid-auto-flow: dense; /* pack later items into holes (use carefully) */
}
dense can improve packing for masonry-like card sizes but reorders visual vs DOM risk for accessibility — prefer DOM order that matches reading order.
Nested composition
Grid and flex compose. Typical pattern: grid for page structure, flex for toolbars and media objects inside cells.
<div class="layout">
<header class="layout__header">…</header>
<aside class="layout__side">…</aside>
<main class="layout__main">
<div class="toolbar">…</div>
<div class="cards">…</div>
</main>
</div>
.layout {
display: grid;
grid-template-columns: 16rem 1fr;
grid-template-areas:
"header header"
"side main";
}
.layout__header { grid-area: header; }
.layout__side { grid-area: side; }
.layout__main { grid-area: main; min-width: 0; }
.toolbar {
display: flex;
align-items: center;
gap: 0.75rem;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
gap: 1rem;
}
min-width: 0 on the main track content again: without it, wide children expand the grid and break the shell.
Grid vs Flexbox (decision table)
| Choose grid when… | Choose flex when… |
|---|---|
| Rows and columns both define the design | One axis drives the layout |
| Alignment of items into a matrix matters | Nav, chips, toolbars, equal-height row of controls |
| You want named areas / full-page scaffolding | Content size should drive packing along one line |
| Overlapping/spanning cells are first-class | You mainly need grow/shrink along a line |
They are not rivals. Use both. Prefer the simpler model that matches the design intent.
Common mistakes
- Using grid for a one-axis toolbar — flex is shorter and clearer.
1frwithoutminmax(0, 1fr)— overflow from min-content.- Forgetting
gapvs margin — double spacing and collapse confusion; usegapin grid/flex. auto-fitvsauto-fill—auto-fitcollapses empty tracks;auto-fillkeeps them. Wrong choice leaves awkward empty columns.- Reordering with placement only — visual order ≠ keyboard/screen reader order. Keep DOM logical.
Interview angle
Explain two-dimensional tracks vs flex’s main axis. Write repeat(auto-fit, minmax(…)) from memory. Place a header full-width with grid-column: 1 / -1 or areas. Call out minmax(0, 1fr) and a11y order.
Live coding: holy-grail layout (header, sidebar, main, footer) with areas, then a responsive card grid inside main.
Related on this site
- Flexbox fundamentals
- CSS Box Model
- Cascade & Specificity
- Grid template areas
- minmax and fr units
- Core Web Vitals
Further reading
- MDN: Basic concepts of grid layout
- MDN: Grid template areas
- web.dev: Grid
- CSS Grid Layout Module Level 2
Related guides
- CSS Grid vs Flexbox When to UseOne-dimensional flex vs two-dimensional grid — decision rules for navs, card grids, page shells, and nested layouts.
- Auto-fit vs Auto-fillauto-fit collapses empty tracks; auto-fill keeps them. Use both with minmax for responsive card grids without media-query soup.
- Centering Everything in CSSCenter with flex, grid, margin auto, and inset — horizontal, vertical, and both — plus the absolute-position and text-align traps.
- CSS Box ModelContent, padding, border, margin, box-sizing, and how the math actually works for layout and overflow.
- Display Block Inline Flex GridHow display changes layout participation — block vs inline vs inline-block, and when flex/grid formatting contexts take over.