The Interactive, the ultimate
CSS Grid
Tutorial

Hands-on demos, sliders, and presets for every grid propertyβ€”learn, experiment, and master two-dimensional layouts with live feedback.

Sections

Defining a Grid

Add display: grid to a container and its direct children become grid items. The container creates a grid formatting context with rows and columns (tracks).

display:
Text before
1
2
3
4
5
6
text after
.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}
πŸ’‘grid is block-level (takes full width). inline-grid flows inline with surrounding content β€” notice the text before/after.

grid-template-columns & grid-template-rows

Define the number and size of columns/rows. Use px, fr, auto, minmax(), or repeat().

columns:
rows:
1
2
3
4
5
6
.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: auto auto;
}

The fr Unit

The fr unit distributes available space proportionally. It's the grid equivalent of flex-grow.

Preset:
1fr
1fr
1fr
.container { grid-template-columns: 1fr 1fr 1fr; }
πŸ’‘1fr = one fraction of available space. If a column is 200px and the rest is 1fr 1fr, those two split whatever remains after the fixed 200px.

gap, row-gap & column-gap

Adds space between tracks without affecting outer edges. Drag the sliders to adjust independently.

row-gap: 12px
col-gap: 12px
1
2
3
4
5
6
.container {
  row-gap: 12px;
  column-gap: 12px;
  /* shorthand: gap: 12px 12px; */
}

grid-column & grid-row

Place items by specifying start/end grid lines. Lines are numbered from 1. Use span to span across tracks.

Item A placement:
A
B
C
D
E
F
G
H
.item-a {
  grid-column: 1 / 2;
  grid-row: 1 / 2;
}
πŸ’‘Grid line numbers start at 1. grid-column: 1 / 3 means "from line 1 to line 3" β€” spanning 2 columns. You can also write span 2.

grid-template-areas

Name regions of your grid with an ASCII-art map. Each item uses grid-area to claim its spot.

Layout:
"header header header" "sidebar main main" "sidebar main main" "footer footer footer"
header
sidebar
main
footer
.container {
  grid-template-areas:
    "header header header"
    "sidebar main main"
    "footer footer footer";
}
.item { grid-area: header; }
πŸ’‘Use . for empty cells: "header header .". Every row must have the same number of columns. Named areas must form rectangles.

justify-items & align-items

justify-items aligns items inside cells along the inline (row) axis. align-items aligns along the block (column) axis.

justify-items:
align-items:
1
2
3
4
5
6
.container {
  justify-items: stretch;
  align-items: stretch;
}
πŸ’‘Default is stretch β€” items fill their entire cell. Switch to start/center/end to see items shrink to content size and move within cells.

justify-content & align-content

When the total grid size is smaller than the container, these properties distribute the tracks (not items).

justify-content:
align-content:
1
2
3
4
5
6
.container {
  grid-template-columns: 100px 100px 100px;
  justify-content: start;
  align-content: start;
}
πŸ’‘These only have visible effect when tracks don't fill the container. That's why we use fixed 100px columns here instead of fr.

justify-self & align-self

Override a single item's alignment within its cell.

justify-self on B:
align-self on B:
A
B
C
D
E
F
.item-b {
  justify-self: stretch;
  align-self: stretch;
}

auto-fill vs auto-fit

Use repeat(auto-fill, minmax(…)) or auto-fit for responsive grids without media queries. Drag the slider to see the difference.

auto-fill
1
2
3
grid-template-columns:
  repeat(auto-fill, minmax(100px, 1fr));
/* creates empty tracks */
auto-fit
1
2
3
grid-template-columns:
  repeat(auto-fit, minmax(100px, 1fr));
/* collapses empty tracks β†’ items stretch */
Container width:600px
πŸ’‘auto-fill creates as many tracks as fit, leaving empties. auto-fit collapses empty tracks so items grow to fill. Visible only when few items + wide container.

min-content, max-content & fit-content

Intrinsic sizing keywords let track sizes respond to their content.

First column:
Some longer text here
Flexible
Short
Flexible
.container { grid-template-columns: auto 1fr; }
πŸ’‘min-content = smallest size without overflow. max-content = ideal size, no wrapping. fit-content(200px) = like max-content but capped at 200px.

Spanning & Overlapping Items

Items can span multiple rows/columns and even overlap using explicit placement + z-index.

Preset:
A (span 2)
B
C
D
E
.a { grid-column: 1 / 3; } /* spans 2 columns */
πŸ’‘Overlapping items stack based on source order by default. Use z-index to control which item appears on top.

Named Grid Lines

Give grid lines names in square brackets, then reference them for placement instead of numbers.

Place A using:
A
B
C
.container {
  grid-template-columns: [sidebar-start] 200px [sidebar-end content-start] 1fr [content-end];
}
.a { grid-column: 1 / 2; grid-row: 1 / 3; }
πŸ’‘Named lines make your CSS self-documenting: grid-column: sidebar-start / sidebar-end is much clearer than 1 / 2.

Nested Grids & Subgrid

A grid item can be a grid container itself. subgrid lets a nested grid inherit parent track lines.

Inner grid:
Inner 1
Inner 2
Inner 3
Outer A
Outer B
Outer C
.inner {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr; /* independent tracks */
}
⚠️subgrid has good browser support (Chrome 117+, Firefox 71+, Safari 16+). It inherits parent lines so nested items align perfectly with outer tracks.

Add & Remove Items

See how the grid auto-places new items. Control implicit row sizing with grid-auto-rows.

4 items
auto-rows:
1
2
3
4
.container {
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: auto;
}
πŸ’‘grid-auto-rows controls the height of implicitly created rows (when items overflow the explicit template).

Common Layouts

Click any card to see the live demo + CSS. Patterns you'll use daily.

πŸ“Š Dashboard
πŸ–ΌοΈ Photo Gallery
πŸ“° Magazine
πŸ₯ž Pancake Stack
πŸ“± Responsive Cards
πŸ“ Sidebar
πŸ“Š Dashboard

Grid vs Flexbox

Both powerful β€” but for different jobs. Use them together.

AspectGridFlexbox
DimensionTwo-dimensional (rows and columns)One-dimensional (row or column)
ApproachLayout-first β€” grid defines structureContent-first β€” items dictate layout
Best forPage layouts, dashboards, galleriesNavbars, toolbars, card rows, centering
Item sizingExplicit tracks (fr, px, auto)Grow/shrink dynamically from content
AlignmentRow axis + column axis + areasMain axis + cross axis
OverlapEasy with grid-area + z-indexNot naturally
Named regionsgrid-template-areas βœ“No equivalent
πŸ’‘Common pattern: Grid for page structure, Flexbox inside each cell for component layout. They complement each other beautifully.

Playground

Mix all properties together. This is where it clicks.

cols:
justify-items:
align-items:
gap: 12px
Hello
CSS
Grid
πŸš€
Layout
Magic

Cheatsheet

Quick reference for every CSS Grid property.

Container Properties

displaygrid | inline-grid
grid-template-columnstrack sizes (px, fr, %, auto, minmax, repeat)
grid-template-rowstrack sizes
grid-template-areasnamed area strings
gap / row-gap / column-gapspacing between tracks
grid-auto-rowssize of implicit rows
grid-auto-columnssize of implicit columns
grid-auto-flowrow | column | dense
justify-itemsstart | end | center | stretch
align-itemsstart | end | center | stretch
justify-contentstart | end | center | space-between | space-around | space-evenly
align-contentstart | end | center | space-between | space-around | stretch

Item Properties

grid-columnstart / end (line numbers or names)
grid-rowstart / end
grid-areaname | row-start / col-start / row-end / col-end
justify-selfstart | end | center | stretch
align-selfstart | end | center | stretch
z-indexstacking order for overlapping items

Common Patterns

repeat(3, 1fr)3 equal columns
repeat(auto-fit, minmax(250px, 1fr))responsive columns
minmax(0, 1fr)fr that can shrink to 0
auto 1fr autoheader, content, footer
subgridinherit parent grid lines