Skip to content

Introduction to CSS Grid — Two-Dimensional Layout

You have spent this module arranging elements in a single direction — rows of cards, horizontal navigation bars, vertically stacked content. CSS Grid solves a different problem: placing elements in rows and columns at the same time.

Flexbox and Grid are not rivals. Most real pages use both — Grid for the overall structure, Flexbox for components inside the grid cells.

Flexbox thinks about content. You define a container, and items decide how much space they take based on their content and flex values. The layout adapts to the items.

Grid thinks about structure first. You define the column and row structure on the container, then items are placed into that structure. The layout drives the content.

Flexbox: [ item ][ item ][ item ] ← items determine spacing
Grid: [ col ][ col ][ col ] ← columns defined first

The analogy: Flexbox is like arranging books on a shelf — the books determine how the shelf fills. Grid is like designing a floor plan — you define the rooms first, then place the furniture.

Use Flexbox when the content should drive the layout. Use Grid when the layout should drive the content.

Activating Grid requires one property on the container:

.team-grid {
display: grid;
}

Like display: flex, this affects only direct children — they become grid items. Deeper descendants are unaffected.

Without grid-template-columns, the browser creates a single-column grid and items stack vertically — identical to normal flow. Grid becomes useful once you define a column structure.

This property defines the column structure. Each value you provide creates a column:

/* Two equal columns */
.about-story-inner {
display: grid;
grid-template-columns: 1fr 1fr;
}
/* Fixed sidebar, flexible content area */
.sidebar-layout {
display: grid;
grid-template-columns: 280px 1fr;
}
/* Three equal columns */
.team-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}

fr stands for fractional unit — a share of the available space after fixed-width columns are subtracted.

grid-template-columns: 1fr 2fr;
/* Second column is twice as wide as the first.
In a 900px container: first = 300px, second = 600px */

fr works like flex-grow in Flexbox — it distributes remaining space proportionally.

Instead of writing 1fr 1fr 1fr, use repeat(count, value):

grid-template-columns: repeat(3, 1fr); /* same as 1fr 1fr 1fr */
grid-template-columns: repeat(4, 200px); /* four 200px columns */

The gap property works in Grid exactly as it does in Flexbox — space between items, no outer margins:

.team-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
}

Control rows and columns independently:

gap: 1.5rem 3rem; /* row-gap: 1.5rem, column-gap: 3rem */

The responsive grid pattern — auto-fill and minmax()

Section titled “The responsive grid pattern — auto-fill and minmax()”

This is Grid’s most practical beginner technique — a multi-column grid that reflows at all viewport widths without any media query:

.team-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 2rem;
}

Breaking it down:

  • auto-fill — create as many columns as will fit in the container width
  • minmax(240px, 1fr) — each column is at least 240px wide, growing up to 1fr of available space

At 900px: three columns. At 550px: two columns. At 300px: one column. No @media required.

This achieves a similar result to the Flexbox flex: 1 1 280px; flex-wrap: wrap pattern from Lesson 05, but Grid distributes columns more precisely — items always fill the row without a single narrow orphan at the end.

A grid item can span more than one column using grid-column: span N:

.blog-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
.post-card:first-child {
grid-column: span 2; /* featured post takes two of the three columns */
}

Useful for a featured item that should stand out from the rest of the grid. The remaining items fill in after it automatically.

You can define row heights, but in most cases you do not need to — the browser creates implicit rows automatically based on content height. Leave grid-template-rows undefined unless you have a specific reason to control vertical sizing.

SituationReach for
Horizontal navigation barFlexbox
Centering a single itemFlexbox
Label stacked above inputFlexbox
Card row that wrapsEither
Image + text side by sideGrid
Team or photo galleryGrid
Page-level structure (header / main / sidebar)Grid
Dashboard with defined rows and columnsGrid

If you are thinking in one direction — “I want items in a row” or “I want items in a column” — reach for Flexbox. If you are thinking in two directions simultaneously — “I want a three-column grid where items also have defined row heights” — reach for Grid.

Apply CSS Grid to the STO about page:

  1. Add a two-column story layout in style.css:
.about-story-inner {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 3rem;
align-items: center;
}

Open about.html on a wide screen — the image placeholder and text block should sit side by side in equal columns.

  1. Apply the responsive team grid:
.team-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 2rem;
}

Resize the browser slowly — watch the guide cards reflow from three columns to two to one with no media query.

  1. In DevTools, click the .team-grid element. A small grid badge appears next to it in the Elements panel — click it to toggle the Grid overlay. The overlay draws column and row lines directly on the page, showing you exactly how the grid is calculated.

  2. Experiment: change grid-template-columns: 1fr 1fr in the story section to grid-template-columns: 1fr 2fr. The text column should now be twice as wide as the image column.

  • Flexbox is one-dimensional (a row or a column); Grid is two-dimensional (rows and columns simultaneously). Use both — they are complementary.
  • display: grid activates Grid on a container; direct children become grid items.
  • grid-template-columns defines the column structure. The fr unit distributes space proportionally: 1fr 2fr makes the second column twice as wide as the first.
  • repeat(count, value) shorthand: repeat(3, 1fr) is equivalent to 1fr 1fr 1fr.
  • gap adds space between grid items without outer margins.
  • repeat(auto-fill, minmax(240px, 1fr)) creates a responsive grid that reflows at all viewport widths without media queries.
  • grid-column: span 2 makes an item span two columns.

Module 06 covers Styling Forms — applying everything you know about selectors, the box model, Flexbox, and transitions to build a complete, accessible contact form.