Phase 2 — CSS
Lesson 0007 • Intermediate

CSS Grid

Flexbox gives you a row or a column. Grid gives you both at the same time. It's how you build full page layouts, dashboards, image galleries, and any design that needs to control rows and columns independently. If Flexbox is a clothesline, Grid is a spreadsheet.

1. When Flexbox Isn't Enough

You just learned Flexbox. It's brilliant for one-dimensional layouts — a navbar, a row of cards, a vertically-centered hero. But consider this: you want a photo gallery where items sit in neat rows and columns, and the layout snaps to a grid. Or a page layout where a sidebar is exactly 300px wide and the main content fills the rest, across multiple rows.

Flexbox can approximate these, but it's fighting its nature. Flexbox distributes items along one axis. CSS Grid was designed from scratch for two-axis control — columns and rows, simultaneously. (MDN: Grid vs. Flexbox)

The Decision Rule

Flexbox: Lay items out in a line (row or column). Let the content drive the size.
Grid: Define a grid structure first, then place items into it. Let the layout drive the size.

In practice, you'll use both together. Grid for the overall page layout. Flexbox inside individual components. They're partners, not competitors.

2. Turning On Grid

Just like Flexbox, one line switches the layout engine:

style.css
.layout {
  display: grid;
}

By itself, display: grid doesn't change much visually — children still stack vertically. The magic comes when you define the grid structure with columns and rows.

3. Defining Columns

The most important Grid property. You declare how many columns you want and how wide each should be:

style.css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr 1fr;
}

This creates three columns: the first is fixed at 200px, the other two share the remaining space equally. Items flow into these columns automatically, left to right, then wrap to the next row. (MDN: grid-template-columns)

Vocabulary

Grid Container
The element with display: grid
Grid Item
A direct child of the grid container
Grid Track
A single row or column — the space between two grid lines
Grid Cell
A single unit of the grid — the intersection of one row and one column
Grid Line
The dividing lines that form the grid structure (numbered from 1)
Grid Area
A rectangular region spanning one or more cells

4. The fr Unit

You already know px, rem, %. Grid introduces a new one: fr — a fraction of the remaining space. It's like flex: 1 but for Grid tracks.

style.css
/* Three equal columns */
grid-template-columns: 1fr 1fr 1fr;

/* Middle column is twice as wide */
grid-template-columns: 1fr 2fr 1fr;

/* Fixed sidebar + flexible main */
grid-template-columns: 300px 1fr;

fr calculates after fixed sizes and gaps are subtracted. So 300px 1fr means: "give 300px to the first column, then give all remaining space to the second." This is the key mental model. (MDN: the fr unit)

💡 Why not percentages? fr is gap-aware. If you write grid-template-columns: 50% 50% and add a gap, the total exceeds 100% and causes overflow. 1fr 1fr never overflows — it divides the space after gaps are removed.

5. Grid Playground — Try It Live

Change the properties below and watch the grid update instantly. Pay attention to how grid-template-columns reshapes the entire layout:

6. Defining Rows

Rows work just like columns:

style.css
.layout {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 100px 200px;
}

This creates two explicitly-defined rows: the first 100px tall, the second 200px tall. If you have more items than cells (3 columns × 2 rows = 6 cells), extra items create implicit rows — rows the browser generates automatically. (MDN: grid-template-rows)

💡 In practice, skip explicit rows Most of the time, you define columns and let rows be auto-generated. You only set grid-template-rows when you need precise row heights (like a dashboard header + body + footer).

7. The gap Property

You know gap from Flexbox — it's exactly the same here:

style.css
/* Equal gap on rows and columns */
gap: 16px;

/* Different row and column gaps */
gap: 24px 16px;  /* row-gap column-gap */

/* Or use the longhand properties */
row-gap: 24px;
column-gap: 16px;

Unlike margins, gap only creates space between tracks — never at the edges. This is why it's better than padding hacks. (MDN: gap)

8. The repeat() Function

Writing 1fr 1fr 1fr 1fr gets tedious. repeat() is the shorthand:

style.css
/* These are identical */
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-columns: repeat(4, 1fr);

/* Mix with fixed sizes */
grid-template-columns: 200px repeat(3, 1fr);

The first argument is the number of repetitions, the second is the track size to repeat. You can mix repeat() with other values freely. (MDN: repeat())

9. Responsive Grids: minmax() + auto-fill

This is the most powerful line of CSS you'll learn today. It creates a fully responsive grid without media queries:

style.css
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 16px;
}

Let's break this down:

Try resizing your browser window with this playground to see it in action:

⚠️ auto-fill vs auto-fit auto-fill creates empty columns if there's leftover space. auto-fit collapses empty columns, stretching items to fill the container. For most use cases (card grids, galleries), auto-fill is what you want. (CSS-Tricks: auto-fill vs auto-fit)

10. Placing Items on the Grid

So far, items flow into cells automatically, left to right, top to bottom. But Grid's real power is explicit placement — telling an item exactly where to sit and how many cells to span.

Grid Lines

Every grid has numbered lines. A 3-column grid has 4 column lines (1 through 4) and rows work the same way:

Visual: 3-column grid line numbers
    col 1    col 2    col 3    col 4
      |        |        |        |
  ----+--------+--------+--------+----  row 1
      | Cell 1 | Cell 2 | Cell 3 |
  ----+--------+--------+--------+----  row 2
      | Cell 4 | Cell 5 | Cell 6 |
  ----+--------+--------+--------+----  row 3

Lines are numbered starting from 1, not 0. A 3-column grid has column lines 1, 2, 3, 4.

Spanning Multiple Cells

Use grid-column and grid-row on a grid item (not the container) to control its placement:

style.css
/* Span columns 1 through 3 (takes up full width of 3-col grid) */
.header {
  grid-column: 1 / 4;
}

/* Span 2 columns from wherever the item naturally lands */
.wide-card {
  grid-column: span 2;
}

/* Span 2 rows */
.sidebar {
  grid-row: 1 / 3;
}

The syntax is start-line / end-line. So 1 / 4 means "start at line 1, end at line 4" (spanning 3 tracks). The span keyword is a shortcut: span 2 means "take up 2 tracks from wherever I am." (MDN: grid-column)

💡 A shortcut for "span everything" grid-column: 1 / -1 means "start at the first line, end at the last line." This spans the entire row regardless of how many columns exist. Negative numbers count from the end.

11. Alignment in Grid

Grid gives you four alignment properties. They work in pairs:

Property Applies To Axis What It Does
justify-items All items (on container) Inline (horizontal) Aligns items within their cells, horizontally
align-items All items (on container) Block (vertical) Aligns items within their cells, vertically
justify-content The grid itself (on container) Inline (horizontal) Aligns the entire grid within the container
align-content The grid itself (on container) Block (vertical) Aligns the entire grid within the container

You'll use justify-items and align-items most often. Both default to stretch, which is why grid items fill their cells by default. Change them to start, end, or center for different effects. (MDN: Box alignment in Grid)

12. Three Patterns You'll Use Constantly

Pattern 1: The Holy Grail Layout

Header, sidebar, main content, footer — the classic page layout, done in 6 lines:

style.css
.page {
  display: grid;
  grid-template-columns: 250px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

.page-header { grid-column: 1 / -1; }
.page-footer { grid-column: 1 / -1; }

The header and footer span all columns with 1 / -1. The sidebar and main content sit in the middle row, each in its own column — automatically.

Pattern 2: Responsive Card Grid

No media queries needed — the single most useful Grid pattern:

style.css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 24px;
}

Pattern 3: Dashboard Grid with Spanning

A dashboard where some widgets are wider or taller than others:

style.css
.dashboard {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
}

.widget-wide  { grid-column: span 2; }
.widget-tall  { grid-row: span 2; }
.widget-big   { grid-column: span 2; grid-row: span 2; }

13. The Grid + Flexbox Decision Cheatsheet

Scenario Use Why
Navigation bar Flexbox One row of items with flexible spacing
Card grid / gallery Grid Two-dimensional layout, neat rows + columns
Sidebar + content page layout Grid Column structure across multiple rows
Centering a single element Either Grid: place-items: center. Flexbox: justify-content + align-items
A button group Flexbox Items in a line, content-sized
Dashboard with spanning widgets Grid Explicit placement and spanning across rows/columns
Overall page structure Grid Header/sidebar/main/footer is a 2D layout problem

14. Test Your Knowledge

Quiz: CSS Grid Fundamentals

What does the fr unit represent in CSS Grid?
Correct. fr divides the remaining space after fixed sizes and gaps are subtracted.
Not quite. fr represents a fraction of the space left after fixed-size tracks and gaps are accounted for.
What does grid-column: 1 / -1 do to a grid item?
Correct. 1 / -1 means "start at line 1, end at the last line" — spanning everything.
Not quite. -1 refers to the last grid line, so 1 / -1 spans from the first to the last line — the entire row.
What does repeat(auto-fill, minmax(250px, 1fr)) achieve?
Correct. The browser creates as many 250px+ columns as fit, and each can grow to fill remaining space.
Not quite. auto-fill tells the browser "fit as many columns as possible," and minmax(250px, 1fr) sets each column's size range.
You need a navigation bar with a logo on the left and links on the right. Which layout tool should you use?
Correct. A navbar is a one-dimensional layout — a single row. Flexbox with space-between is the right tool.
Think about dimensions: a navbar is one row of items. That's a one-dimensional problem — Flexbox territory.
Why is fr preferred over % for Grid column sizing?
Correct. fr divides space after gaps are subtracted, preventing overflow. 50% + 50% + gap exceeds 100%.
The key issue: 50% + 50% already fills the container, but then gap adds extra space, causing overflow. fr is gap-aware.
A 3-column grid has how many column lines?
Correct. Column lines = columns + 1. A 3-column grid has lines 1, 2, 3, and 4.
Think of it like fence posts: 3 sections of fence need 4 posts. 3 columns need 4 lines. They're numbered starting from 1.
–

Quiz Complete!

Review any concepts you got wrong using the CSS Grid cheatsheet.

15. Retrieval Practice: Fill In The Blanks

Close your eyes, think, then type. Effortful recall is what moves knowledge from short-term to long-term memory.

.container {
  display: ;
  grid-template-columns: repeat( , minmax(250px, 1fr));
   : 24px;
}
.full-width-header {
  grid-column: 1 / ;
}

16. Build Challenge: Dashboard Layout with Grid

Build a mini analytics dashboard from scratch. This is a real-world layout — the kind you'd see in any SaaS product. Use Grid for the overall page structure, and Flexbox for components inside each widget.

  1. Create practices/lesson7-dashboard.html and practices/lesson7-style.css
  2. Build the page layout using Grid:
    • Full-width header spanning all columns: grid-column: 1 / -1
    • A 4-column grid for the main content area
    • Full-width footer spanning all columns
  3. Build a stats row — 4 cards in a row:
    • Each card shows a metric name and number (e.g., "Total Users: 12,847")
    • Use repeat(4, 1fr) or repeat(auto-fill, minmax(200px, 1fr))
  4. Build a widget area below the stats:
    • One "wide" widget spanning 2 columns (a chart placeholder)
    • Two regular widgets in the remaining columns
    • Use grid-column: span 2 for the wide one
  5. Make it responsive:
    • Use repeat(auto-fill, minmax(280px, 1fr)) so cards reflow automatically
    • Or add one @media query to switch to 1 column on mobile
⚠️ Write It Yourself Use the CSS Grid reference sheet for property names. Use the Flexbox cheatsheet for components inside widgets. But every layout decision should come from your own head.

Primary Sources: CSS-Tricks: A Complete Guide to CSS Grid is the canonical Grid reference — bookmark it alongside the Flexbox guide. Also: MDN: CSS Grid Layout for the official spec, and Kevin Powell for visual demonstrations of Grid in action.

Finished the build? Type /teach and show me your dashboard. I'll review the layout, check your Grid + Flexbox decisions, and then we'll move on to Responsive Design.

💬 Questions? Ask your teacher. Grid can feel complex at first — that's normal. If the line-number system, minmax(), or placement syntax is unclear, ask me. I'll explain it differently until it clicks. Don't move on with uncertainty.