Skip to main content

🧱 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 the fr unit
  • Apply sizing functions β€” repeat(), minmax(), auto-fill/auto-fit β€” to build responsive grids
  • Predict how the implicit grid and grid-auto-flow place 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.
flowchart LR Q{One axis or two?} -->|One row or column| F[Use Flexbox] Q -->|Rows AND columns| G[Use CSS Grid] F --> F1[Navbars, button rows, tag lists] G --> G1[Page shells, dashboards, galleries]

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.

TermWhat it isCity-planning analogy
Grid containerThe element with display: gridThe city limits
Grid itemA direct child of the containerA building
Grid lineThe dividing lines between tracks (numbered from 1)The streets
Grid trackThe space between two adjacent lines β€” a row or columnA city block
Grid cellOne row Γ— one column β€” the smallest unitA single lot
Grid areaA rectangle of one or more cellsA neighborhood
GapSpace between tracks (the "gutter")The width of the streets
Anatomy of a CSS grid A grid container split by numbered grid lines into tracks and cells, with one grid area spanning four cells and a single highlighted cell. Grid container 1 2 3 4 Grid area Grid cell a track (row 1)
Figure 1 β€” Numbered grid lines carve the container into tracks and cells. A grid area is any rectangle of cells; here it spans two columns and one row.

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

KeywordSizes the track to…
autoits content, then absorbs leftover space where it can
min-contentthe smallest it can be without overflowing (longest unbreakable word)
max-contentas 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

  1. At least six cards, each roughly 260px minimum wide.
  2. The gallery gains and loses columns automatically with no media queries.
  3. A uniform 24px gap between all cards.
  4. 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 fr for flexible tracks so gaps are handled automatically.
  • Combine minmax() with auto-fit/auto-fill for 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 px tracks β€” they overflow on small screens.
  • Don't forget the gap when hand-calculating percentages; use fr and skip the math.
  • Don't assume display: grid alone 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; the fr unit shares leftover space and respects gaps.
  • repeat(), minmax(), and auto-fit/auto-fill together give you responsive layouts with no media queries.
  • Extra items land in the implicit grid, sized by grid-auto-rows/columns and flowed by grid-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

πŸš€ 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.