π§± Grid Layout Fundamentals
CSS Grid is the first layout system built for two dimensions at once β rows and columns, together. In this lesson you'll build a mental model for Grid, learn its vocabulary, and write your first real grids, including a responsive gallery that reflows itself with zero media queries.
π― Learning Objectives
By the end of this lesson, you will be able to:
- Explain how two-dimensional Grid differs from one-dimensional Flexbox, and when to reach for each
- Use the core Grid vocabulary correctly β container, item, line, track, cell, area, gap
- Define grid structure with
grid-template-columns,grid-template-rows, and thefrunit - Apply sizing functions β
repeat(),minmax(),auto-fill/auto-fitβ to build responsive grids - Predict how the implicit grid and
grid-auto-flowplace extra items
Estimated Time: 35β45 minutes β’ Difficulty: Intermediate
Hands-on: Build a responsive card gallery that adds and removes columns as the window resizes.
In This Lesson
Why Grid Exists
For most of the web's history, "layout" meant bending tools that were never designed for it. Developers stacked HTML tables, floated boxes and cleared them, or nested div after div just to get a sidebar to sit beside some content. Each technique was a workaround, and each one leaked into your markup.
CSS Grid Layout is the first system designed specifically for laying out the two-dimensional web. You describe a grid of rows and columns on a parent element, and its children snap into that grid. The structure lives entirely in CSS, so your HTML stays clean and semantic.
π‘ Jen Simmons, a web-standards advocate at Apple, put it well: Grid brings a genuinely new approach to problems we had been hacking around for as long as we'd been making websites. It is not a slightly-better float β it is a different way of thinking about the page.
π One-dimensional vs. two-dimensional
One-dimensional layout arranges items along a single axis β a row or a column. That's Flexbox's specialty.
Two-dimensional layout controls rows and columns at the same time, so an item's horizontal and vertical position are decided together. That's what Grid unlocks.
Grid vs. Flexbox
Grid and Flexbox are partners, not rivals. The clearest way to choose is to ask: am I arranging things in one direction, or in two at once?
- Flexbox is like arranging books on a single shelf. You control how they spread and align along that one line.
- Grid is like arranging books in a whole bookcase. You control both the shelf (row) and the slot on the shelf (column) for every book.
In real projects you almost always use both: Grid lays out the overall page shell, and Flexbox aligns the contents inside individual grid areas β the nav items inside a header, the buttons inside a card footer.
β Rule of thumb
Reach for Grid when the layout comes first (you're placing regions on a page) and Flexbox when the content comes first (you're distributing however many items happen to be there along one line).
The Grid Vocabulary
Grid has seven words worth memorizing. Learn them once and every article, error message, and DevTools panel will make sense.
| Term | What it is | City-planning analogy |
|---|---|---|
| Grid container | The element with display: grid | The city limits |
| Grid item | A direct child of the container | A building |
| Grid line | The dividing lines between tracks (numbered from 1) | The streets |
| Grid track | The space between two adjacent lines β a row or column | A city block |
| Grid cell | One row Γ one column β the smallest unit | A single lot |
| Grid area | A rectangle of one or more cells | A neighborhood |
| Gap | Space between tracks (the "gutter") | The width of the streets |
Defining Tracks & the fr Unit
You turn any element into a grid container with a single declaration:
.container {
display: grid;
}
Just like Flexbox, this makes the children into grid items. But unlike Flexbox, nothing visible happens yet β a grid with no defined tracks is just a single-column stack. You give it shape with grid-template-columns and grid-template-rows:
.container {
display: grid;
grid-template-columns: 200px 1fr 200px; /* 3 columns */
grid-template-rows: auto 400px; /* 2 rows */
gap: 20px;
}
That creates two fixed 200px side columns with a flexible middle, plus a content-sized row above a 400px row.
The fr unit
The fraction unit (fr) is unique to Grid. It represents a share of the leftover space after fixed sizes and gaps are subtracted. Think of slicing a pizza: give one column 1fr and another 2fr, and the second gets a slice twice as big.
/* Middle column is twice as wide as the outer two */
grid-template-columns: 1fr 2fr 1fr;
/* Fixed rails, flexible center β a classic app shell */
grid-template-columns: 240px 1fr;
β οΈ Percent vs. fr
1fr 1fr 1fr and 33.33% 33.33% 33.33% look similar, but only fr automatically accounts for the gap. Three 33.33% columns plus gaps overflow the container; three 1fr columns never do. Prefer fr.
Track-Sizing Toolbox
Grid gives you a small but powerful set of ways to size tracks. Here are the ones you'll use daily.
repeat() β stop typing the same value
grid-template-columns: repeat(3, 1fr); /* = 1fr 1fr 1fr */
grid-template-columns: repeat(3, 100px 200px); /* = 100px 200px 100px 200px 100px 200px */
grid-template-columns: 100px repeat(2, 1fr) 100px; /* mix freely */
minmax(min, max) β a size range
minmax() sets a floor and a ceiling for a track. A balloon analogy fits: it expands as it fills, but won't grow past its limit.
/* Never smaller than 100px, never wider than 200px */
grid-template-columns: minmax(100px, 200px) 1fr 1fr;
/* Rows that grow with content but never collapse below 120px */
grid-auto-rows: minmax(120px, auto);
Content keywords: auto, min-content, max-content
| Keyword | Sizes the track to⦠|
|---|---|
auto | its content, then absorbs leftover space where it can |
min-content | the smallest it can be without overflowing (longest unbreakable word) |
max-content | as wide as needed so nothing wraps |
/* Sidebar hugs its content; main content takes the rest */
grid-template-columns: max-content 1fr;
auto-fill and auto-fit β let the browser count
Combined with minmax(), these keywords ask the browser to fit as many tracks as it can. They are the secret behind media-query-free responsive grids (next section).
auto-fillβ creates as many tracks as fit, keeping empty ones. Like reserving theater seats even if some stay empty.auto-fitβ creates tracks only for real items and collapses the empties, letting existing items stretch to fill. Like setting out seats only for the guests who showed up.
Gaps & the Implicit Grid
Gaps are gutters, not margins
The gap property spaces tracks apart without adding space at the outer edges β no more fragile margin math.
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
row-gap: 30px; /* between rows */
column-gap: 20px; /* between columns */
gap: 30px 20px; /* shorthand: row-gap column-gap */
gap: 20px; /* one value = both */
}
Explicit vs. implicit grid
The tracks you declare in grid-template-* form the explicit grid. When you have more items than defined cells, Grid quietly manufactures new tracks β the implicit grid. You control the size and direction of those auto-created tracks:
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* explicit columns */
grid-auto-rows: 200px; /* extra rows are 200px tall */
grid-auto-flow: row; /* fill rows first (default) */
}
It's like a restaurant with a planned seating chart (explicit) that wheels out extra tables when more guests than expected arrive (implicit). The grid-auto-flow property decides the direction items fill β row (default), column, or dense to backfill gaps left by larger items.
Responsive Grids Without Media Queries
Here is Grid's party trick. This single rule builds a gallery that adds and removes columns automatically as the viewport changes β no breakpoints, no JavaScript:
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}
Read it right-to-left: each column is at least 250px and at most one flexible fraction. The browser fits as many 250px+ columns as the width allows, then auto-fit stretches them to share the leftover space. Shrink the window and a column drops away; widen it and one appears.
π‘ auto-fit vs. auto-fill in this pattern
With a full row of items they behave identically. The difference shows with few items: auto-fit lets your handful of cards stretch across the whole row, while auto-fill keeps phantom empty columns, leaving the cards at their minimum width. For galleries, auto-fit usually looks best.
What the browser effectively computes at 820px wide (gap 20px):
820 = nΒ·250 + (nβ1)Β·20 β n = 3 columns, each grows to ~253px
Hands-on Exercise
ποΈ Build a Self-Reflowing Card Gallery
Objective: Create a product-card gallery that reflows its columns as the window resizes, using only Grid.
Requirements
- At least six cards, each roughly 260px minimum wide.
- The gallery gains and loses columns automatically with no media queries.
- A uniform 24px gap between all cards.
- Every card is the same height regardless of its text length.
π‘ Hint
Reach for repeat(auto-fit, minmax(260px, 1fr)) on the gallery. For equal heights, remember that grid items stretch to fill their track by default, so as long as each card is a direct grid item, matching heights come for free.
β Solution
<div class="gallery">
<article class="card"><h3>Item 1</h3><p>Short.</p></article>
<article class="card"><h3>Item 2</h3><p>A much longer description that wraps across several lines.</p></article>
<!-- four more cards -->
</div>
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 24px;
}
.card {
padding: 1.25rem;
border: 1px solid #ddd;
border-radius: 10px;
/* No height needed β items stretch to the tallest in their row. */
}
Resize the browser: the column count changes on its own, and every card in a row shares the tallest card's height. That's Grid doing the responsive work you used to write by hand.
Best Practices
β Do
- Use
frfor flexible tracks so gaps are handled automatically. - Combine
minmax()withauto-fit/auto-fillfor responsive grids before you reach for a media query. - Let Grid own the page shell and Flexbox own the inside of components.
- Inspect grids with your browser's DevTools "Grid" overlay β it draws the lines and numbers for you.
β οΈ Don't
- Don't paper the page with fixed
pxtracks β they overflow on small screens. - Don't forget the
gapwhen hand-calculating percentages; usefrand skip the math. - Don't assume
display: gridalone lays anything out β you must define tracks.
Summary & Quiz
π Key Takeaways
- Grid is two-dimensional β it controls rows and columns together, unlike one-dimensional Flexbox.
- Learn the seven terms: container, item, line, track, cell, area, gap.
- Define structure with
grid-template-columns/rows; thefrunit shares leftover space and respects gaps. repeat(),minmax(), andauto-fit/auto-filltogether give you responsive layouts with no media queries.- Extra items land in the implicit grid, sized by
grid-auto-rows/columnsand flowed bygrid-auto-flow.
π― Quick Quiz
Question 1: What most clearly distinguishes CSS Grid from Flexbox?
Question 2: In grid-template-columns: 1fr 2fr 1fr, how wide is the middle column relative to each outer column?
Question 3: Which declaration builds a gallery that adds/removes columns as the viewport resizes, with no media queries?
π Further Reading
- CSS-Tricks β A Complete Guide to CSS Grid
- MDN β CSS Grid Layout
- Grid Garden β an interactive learning game
- Grid by Example (Rachel Andrew)
π What's Next?
You can now build a grid and size its tracks. Next we go deeper into the container side β named lines, grid-template-areas, the auto and alignment properties, and the powerful shorthands that tie them together.
π Great start!
The hardest part of Grid is the vocabulary, and you own it now. Everything from here is combinations of what you just learned.