CSS Grid

Introduction

CSS Grid is a two-dimensional layout system that lets you create complex layouts with rows AND columns simultaneously. While Flexbox excels at one-dimensional layouts (a row or a column), Grid is designed for laying out entire pages or complex UI sections.

What Problems Does Grid Solve?

  • Two-dimensional layouts - Control both rows and columns at once
  • Page structure - Create headers, sidebars, main content, and footers easily
  • Responsive galleries - Cards that automatically adjust to fill available space
  • Complex alignments - Items that span multiple rows or columns

Grid vs Flexbox

Understanding when to use each is crucial:

FlexboxGrid
One-dimensional (row OR column)Two-dimensional (rows AND columns)
Content-driven - items determine layoutLayout-driven - you define the structure
Best for components (navbars, cards)Best for page layouts (overall structure)
Items flow and wrap naturallyItems placed in defined cells

Use Flexbox for:

  • Navigation menus
  • Button groups
  • Card content layout
  • Centering elements
  • Components where items should flow naturally

Use Grid for:

  • Page layouts (header, sidebar, main, footer)
  • Image galleries
  • Card grids
  • Any layout that needs precise row AND column control

Analogy

  • Flexbox = Arranging books on a shelf (one dimension)
  • Grid = Arranging furniture in a room (two dimensions)
Pro tip: You can (and should!) use both together - Grid for the page layout, Flexbox for components within the grid cells.

Creating a Grid Container

display: grid

Creates a grid container and enables grid layout.

.container {
  display: grid;
}

grid-template-columns

Defines the number and size of columns.

.container {
  display: grid;
  grid-template-columns: 200px 200px 200px; /* Three 200px columns */
}
grid-template-columns: 200px 200px 200px

┌──────────┬──────────┬──────────┐
│  200px   │  200px   │  200px   │
│          │          │          │
└──────────┴──────────┴──────────┘

grid-template-rows

Defines the number and size of rows.

.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 100px 200px; /* First row 100px, second row 200px */
}

gap

Sets spacing between grid cells (same as in Flexbox).

.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 20px;           /* 20px gap between all cells */
  /* Or specify separately: */
  row-gap: 10px;
  column-gap: 20px;
}

The fr Unit

The fr (fraction) unit represents a fraction of the available space. It’s similar to flex-grow in Flexbox.

.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr; /* Three equal columns */
}
grid-template-columns: 1fr 1fr 1fr (container width: 900px)

┌──────────┬──────────┬──────────┐
│  300px   │  300px   │  300px   │
│   (1fr)  │   (1fr)  │   (1fr)  │
└──────────┴──────────┴──────────┘

Mixing fr with fixed units

.container {
  display: grid;
  grid-template-columns: 250px 1fr 1fr; /* Fixed sidebar, two flexible columns */
}
grid-template-columns: 250px 1fr 1fr (container width: 1000px)

┌──────────┬────────────┬────────────┐
│  250px   │   375px    │   375px    │
│ (fixed)  │   (1fr)    │   (1fr)    │
└──────────┴────────────┴────────────┘
               remaining space split equally

Common pattern: Sidebar layout

.page-layout {
  display: grid;
  grid-template-columns: 250px 1fr; /* Fixed sidebar, flexible main content */
}

The repeat() Function

Simplifies defining multiple columns or rows of the same size.

/* Instead of: */
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;

/* Write: */
grid-template-columns: repeat(6, 1fr); /* Six equal columns */

Syntax

repeat(number-of-times, size)

Examples

grid-template-columns: repeat(3, 1fr);        /* Three equal columns */
grid-template-columns: repeat(4, 200px);      /* Four 200px columns */
grid-template-columns: repeat(3, 1fr 2fr);    /* Pattern: 1fr, 2fr, 1fr, 2fr, 1fr, 2fr */

Understanding Grid Lines

This is the most confusing concept in Grid - but essential to understand.

Grid lines are numbered starting at 1, not 0!

Grid lines are the lines between cells, not the cells themselves.

        Line 1    Line 2    Line 3    Line 4
           ↓         ↓         ↓         ↓
           │         │         │         │
     ──────┼─────────┼─────────┼─────────┼────── Line 1
           │  Cell   │  Cell   │  Cell   │
           │   1     │   2     │   3     │
     ──────┼─────────┼─────────┼─────────┼────── Line 2
           │  Cell   │  Cell   │  Cell   │
           │   4     │   5     │   6     │
     ──────┼─────────┼─────────┼─────────┼────── Line 3
Key insight: A grid with 3 columns has 4 vertical lines.

Why lines, not cells?

Grid lines let you specify where items start and end, allowing items to span multiple cells.


Positioning Grid Items

grid-column

Specifies which column lines an item spans.

.item {
  grid-column: 1 / 3; /* Start at line 1, end at line 3 (spans 2 columns) */
}
grid-column: 1 / 3

Line 1    Line 2    Line 3
   │         │         │
   │◄────────┼────────►│
   │    Item spans     │
   │    columns 1-2    │

grid-row

Specifies which row lines an item spans.

.item {
  grid-row: 1 / 3; /* Start at line 1, end at line 3 (spans 2 rows) */
}

Using span

Instead of specifying end lines, use span to say how many cells to cover:

.item {
  grid-column: 1 / span 2; /* Start at line 1, span 2 columns */
  /* Same as: grid-column: 1 / 3; */
}

grid-area (Shorthand)

Combines row and column positioning:

.item {
  grid-area: 1 / 1 / 3 / 4;
  /* row-start / column-start / row-end / column-end */
}

Example: Header spanning full width

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.header {
  grid-column: 1 / -1; /* -1 means "last line" */
}
┌─────────────────────────────────┐
│           Header                │ ← spans all columns (1 / -1)
├──────────┬──────────┬──────────┤
│   Item   │   Item   │   Item   │
└──────────┴──────────┴──────────┘

Advanced Grid Features

minmax()

Sets minimum and maximum sizes for tracks.

.container {
  display: grid;
  grid-template-columns: minmax(200px, 1fr) 2fr;
  /* First column: at least 200px, but can grow */
}

grid-auto-rows

Sets the size of automatically created rows (when items overflow the defined rows).

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 200px; /* Any new rows will be 200px tall */
}

With minmax for flexible heights:

.container {
  grid-auto-rows: minmax(150px, auto); /* At least 150px, grows with content */
}

auto-fit and auto-fill

Create responsive grids without media queries!

auto-fit: Columns stretch to fill available space auto-fill: Creates as many columns as fit, even if empty

The “Magic Formula” for Responsive Grids:

.container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

This is powerful because:

  • Each card is at least 200px wide
  • Cards grow to fill available space
  • Cards automatically wrap to new rows when needed
  • No media queries required!
Wide screen:
┌────────┬────────┬────────┬────────┐
│  Card  │  Card  │  Card  │  Card  │
└────────┴────────┴────────┴────────┘

Narrow screen (same CSS):
┌────────────┬────────────┐
│    Card    │    Card    │
├────────────┼────────────┤
│    Card    │    Card    │
└────────────┴────────────┘

Grid Template Areas

Define your layout visually using named areas (optional but very readable).

.container {
  display: grid;
  grid-template-columns: 200px 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; }
┌────────────────────────────┐
│          header            │
├─────────┬──────────────────┤
│         │                  │
│ sidebar │      main        │
│         │                  │
├─────────┴──────────────────┤
│          footer            │
└────────────────────────────┘
This is very readable - you can literally see the layout structure in your CSS!

Combining Grid and Flexbox

Use them together for the best results:

  • Grid for the overall page structure
  • Flexbox for components within grid cells

Example: Netflix-style page layout

/* Page layout with Grid */
.page {
  display: grid;
  grid-template-rows: auto 1fr auto; /* Header, main, footer */
  min-height: 100vh;
}

/* Navigation with Flexbox */
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* Movie cards grid */
.movie-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 20px;
}

/* Individual card with Flexbox */
.movie-card {
  display: flex;
  flex-direction: column;
}

Common Patterns

Basic Page Layout

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

.header {
  grid-column: 1 / -1; /* Span full width */
}

.footer {
  grid-column: 1 / -1; /* Span full width */
}

Responsive Card Gallery

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1.5rem;
}

Holy Grail Layout (Header, Footer, Sidebar, Main)

.layout {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  grid-template-columns: 250px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

Sticky Footer (Content pushes footer down)

.page {
  display: grid;
  grid-template-rows: auto 1fr auto; /* Header, main (grows), footer */
  min-height: 100vh;
}

Troubleshooting & Common Mistakes

Items not spanning correctly?
  • Remember: grid lines are numbered starting at 1, not 0
  • A 3-column grid has 4 vertical lines
  • Use -1 to refer to the last line
Grid items overlapping?
  • Check your grid-column and grid-row values
  • Make sure items aren’t assigned to the same cells
Grid not taking full height?
  • Add min-height: 100vh to the grid container
  • Use 1fr for the main content row
Responsive grid not working?
  • Use auto-fit with minmax() for automatic responsiveness
  • Example: repeat(auto-fit, minmax(200px, 1fr))
Want to debug?
  • Open browser DevTools (F12)
  • Click on your grid container in the Elements panel
  • Look for the “grid” badge - click it to show grid lines
  • Chrome and Firefox have excellent Grid inspectors

Key Takeaways

🎯
  • Grid is two-dimensional - controls rows AND columns simultaneously
  • Grid is layout-first - define the structure, then place items
  • The fr unit is like flex-grow - distributes available space
  • Grid lines are numbered 1, 2, 3… (not 0-indexed)
  • repeat(auto-fit, minmax(200px, 1fr)) is the magic formula for responsive grids
  • Use Grid for page layouts, Flexbox for components
  • You can (and should) use Grid and Flexbox together
  • Browser DevTools have excellent Grid debugging tools

Additional Resources

Official Documentation

Interactive Learning

Visual References

Tools

  • Browser DevTools Grid Inspector - Built into Chrome and Firefox
  • Firefox Grid Inspector - Particularly powerful for debugging

Video Resources