Episode 1 — Fundamentals / 1.8 — CSS Layout Mastery
1.8.c — CSS Grid
In one sentence: CSS Grid is a two-dimensional layout engine that lets you define rows and columns simultaneously, place items by line numbers or named areas, and build complex page layouts that were previously impossible without hacks.
Navigation: ← 1.8.b — Common Layout Patterns · 1.8.d — Combining Grid & Flex →
1. Grid container and grid items
.container {
display: grid; /* or inline-grid */
}
Direct children become grid items. Like flexbox, only direct children participate — nested elements follow their own flow unless they are also grid containers.
2. Defining columns and rows
.grid {
grid-template-columns: 200px 1fr 200px;
grid-template-rows: 80px 1fr;
}
200px 1fr 200px
┌──────────┬────────────┬──────────┐
80px │ cell 1 │ cell 2 │ cell 3 │
├──────────┼────────────┼──────────┤
1fr │ cell 4 │ cell 5 │ cell 6 │
└──────────┴────────────┴──────────┘
3. The fr unit
fr stands for fraction of available space. After fixed-size tracks are resolved, remaining space is divided among fr tracks proportionally.
grid-template-columns: 1fr 2fr 1fr;
/* 25% — 50% — 25% of remaining space */
fr is superior to percentages because it accounts for gap automatically — no overflow math.
4. repeat() and minmax()
repeat()
grid-template-columns: repeat(4, 1fr); /* four equal columns */
grid-template-columns: repeat(3, 100px 1fr); /* alternating pattern × 3 */
minmax()
grid-template-columns: repeat(3, minmax(200px, 1fr));
/* each column: at least 200px, at most equal share */
Combined: responsive grid
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
This is the single most useful line in CSS Grid — it creates a responsive multi-column layout with no media queries.
5. Grid gaps
.grid {
gap: 16px; /* shorthand: row-gap and column-gap */
gap: 16px 24px; /* row-gap column-gap */
row-gap: 16px;
column-gap: 24px;
}
Gaps create space between tracks, not at the edges — same as flexbox gap.
6. grid-template-areas — named regions
Define layout with ASCII art:
.page {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
Rules for named areas:
- Each row is a quoted string with space-separated names.
- Names must form rectangles (no L-shapes or T-shapes).
- Use
.for empty cells:"sidebar . main".
7. Line-based placement
Grid lines are numbered starting at 1 (not 0).
.item {
grid-column: 1 / 3; /* start at line 1, end at line 3 (spans 2 columns) */
grid-row: 2 / 4; /* start at line 2, end at line 4 (spans 2 rows) */
}
Line: 1 2 3 4
│ │ │ │
▼ ▼ ▼ ▼
┌──────┬──────┬──────┐
Line 1 │ │ │ │
├──────┼──────┼──────┤
Line 2 │ │ │ │
├──────┼──────┼──────┤
Line 3 │ │ │ │
└──────┴──────┴──────┘
Line 4
The span keyword
.item {
grid-column: 2 / span 3; /* start at line 2, span 3 columns */
grid-row: span 2; /* span 2 rows from auto-placed position */
}
8. Implicit vs explicit grid
Explicit grid = tracks you define with grid-template-columns / grid-template-rows.
Implicit grid = tracks the browser creates automatically when items are placed beyond the explicit grid.
.grid {
grid-template-columns: repeat(3, 1fr);
/* only 3 columns defined explicitly */
grid-auto-rows: 200px; /* implicit rows get 200px height */
}
| Property | Controls |
|---|---|
grid-auto-rows | Height of implicitly created rows |
grid-auto-columns | Width of implicitly created columns |
grid-auto-flow | row (default), column, dense — placement direction |
grid-auto-flow: dense fills gaps left by larger items — useful for masonry-like effects but can reorder content visually.
9. auto-fill vs auto-fit
Both create responsive columns, but they differ when there are fewer items than available columns:
/* auto-fill: keeps empty tracks → items stay at min size */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* auto-fit: collapses empty tracks → items stretch to fill */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
Container: 1000px wide, minmax(200px, 1fr), only 2 items
auto-fill (5 tracks created, 3 empty):
┌──────┐ ┌──────┐ ┌ ┐ ┌ ┐ ┌ ┐
│ Item │ │ Item │ │empty │ │empty │ │empty │
└──────┘ └──────┘ └ ┘ └ ┘ └ ┘
auto-fit (empty tracks collapsed, items stretch):
┌─────────────────────┐ ┌─────────────────────┐
│ Item │ │ Item │
└─────────────────────┘ └─────────────────────┘
Rule of thumb: Use auto-fit when you want items to stretch; auto-fill when you want consistent column sizes.
10. Subgrid (brief)
Subgrid lets a grid item's children align to the parent grid's tracks instead of creating an independent grid.
.card {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid; /* inherit parent's row tracks */
}
This solves the classic problem of aligning card headers, bodies, and footers across a row of cards. Browser support is now solid in modern browsers.
11. Key takeaways
- Grid is two-dimensional — it controls rows and columns simultaneously.
frdivides free space;minmax()sets boundaries;repeat()avoids repetition.- Named areas make complex layouts readable and maintainable.
- Line-based placement gives precise control with
grid-column/grid-row. auto-fillkeeps empty tracks;auto-fitcollapses them.- Subgrid aligns nested grids to parent tracks — great for card layouts.
Explain-It Challenge
Explain without notes:
- Why is
frbetter than percentages for grid columns whengapis involved? - What is the difference between explicit and implicit grid tracks?
- When would you choose
auto-filloverauto-fit(or vice versa)?
Navigation: ← 1.8.b — Common Layout Patterns · 1.8.d — Combining Grid & Flex →