πŸ”²
CodingπŸŽ“ Ages 14-18Intermediate 13 min read

CSS Grid Layout Basics

Learn CSS Grid: build two-dimensional layouts with grid-template-columns, rows, gap, fr units, repeat() and grid spanning. Includes a full responsive photo-gallery example, a try-it section and a quiz.

Key takeaways

  • display: grid creates a two-dimensional layout of rows AND columns
  • grid-template-columns defines how many columns there are and how wide they are
  • The fr unit splits leftover space into flexible fractions
  • repeat() and gap keep grid definitions short and evenly spaced
  • grid-column: span 2 lets an item stretch across multiple tracks

A grid for two directions

CSS Flexbox is brilliant for arranging things in a single line β€” a row of buttons or a column of cards. But real page layouts often need control in two directions at once: a header across the top, a sidebar on the left, content in the middle, all in neat rows and columns. That's exactly what CSS Grid is built for.

Grid is a two-dimensional layout system. You define a set of columns and rows on a container, and then place items into the cells of that grid. In this lesson you'll learn the core properties and build a responsive photo gallery.

Step 1: turn on the grid

Just like Flexbox, Grid starts on the container. Set display: grid and then describe the columns:

.gallery {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

With HTML like:

<div class="gallery">
  <div class="cell">1</div>
  <div class="cell">2</div>
  <div class="cell">3</div>
  <div class="cell">4</div>
  <div class="cell">5</div>
  <div class="cell">6</div>
</div>

grid-template-columns: 1fr 1fr 1fr says "make three columns, each one fraction wide." The six cells flow into the grid three across, automatically wrapping onto new rows.

The fr unit

The star of Grid is the fr unit, short for fraction. It divides up the leftover space in the container. If you write three 1fr columns, each takes one third. Write 2fr 1fr 1fr and the first column is twice as wide as the others:

.layout {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;  /* 50% / 25% / 25% */
}

Unlike percentages, fr automatically accounts for the gap between tracks, so your columns never overflow. You can also mix units β€” 250px 1fr gives a fixed 250px sidebar and a flexible main area that takes the rest.

Step 2: repeat() and gap

Writing 1fr 1fr 1fr 1fr gets tedious. The repeat() function shortens it:

.gallery {
  display: grid;
  grid-template-columns: repeat(4, 1fr);  /* four equal columns */
  gap: 16px;                              /* space between cells */
}

gap adds even spacing between every row and column β€” no margins required. You can set them separately with row-gap and column-gap if needed.

Step 3: spanning across cells

By default each item fills one cell. To make an item stretch across more, use grid-column or grid-row with span:

.feature {
  grid-column: span 2;   /* take up two columns */
  grid-row: span 2;      /* and two rows */
}

This is how you build a magazine-style layout where one big image dominates while smaller items fill in around it.

Step 4: a responsive grid with no media queries

Here's a trick that feels like magic. Combine repeat() with auto-fit and minmax():

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

This reads as: "fit as many columns as you can, where each is at least 150px wide but can grow to share the space." On a wide screen you might get five columns; on a phone it collapses to one β€” all without a single media query. (When you do want explicit breakpoints, see Responsive Web Design Basics.)

A complete worked example

Save this as gallery.html and open it. Resize the window and watch the columns appear and disappear automatically.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Grid Gallery</title>
  <style>
    body { font-family: sans-serif; margin: 0; padding: 24px; background: #0f172a; }

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

    .tile {
      background: #38bdf8;
      color: #0f172a;
      font-size: 2rem;
      font-weight: bold;
      display: flex;
      align-items: center;
      justify-content: center;
      aspect-ratio: 1;          /* keeps each tile square */
      border-radius: 12px;
    }

    /* Make the first tile a big feature spanning 2 x 2 */
    .tile.feature {
      grid-column: span 2;
      grid-row: span 2;
      background: #f472b6;
      aspect-ratio: auto;
    }
  </style>
</head>
<body>
  <div class="gallery">
    <div class="tile feature">β˜…</div>
    <div class="tile">1</div>
    <div class="tile">2</div>
    <div class="tile">3</div>
    <div class="tile">4</div>
    <div class="tile">5</div>
    <div class="tile">6</div>
    <div class="tile">7</div>
  </div>
</body>
</html>

Reading the result: the container is a responsive grid that fits as many 150px+ columns as the screen allows. The first tile carries the feature class, so it spans two columns and two rows to become a focal point. Inside each tile, Flexbox (display: flex) centers the number β€” Grid and Flexbox cooperating, each doing what it does best.

Try it yourself

  1. Change the minimum. Set minmax(100px, 1fr) and then minmax(250px, 1fr). Watch how the column count changes at the same window width.
  2. Move the feature. Add the feature class to a different tile and see the others reflow around the larger cell.
  3. Make a page layout. Build a new grid with grid-template-columns: 200px 1fr and two rows for a classic sidebar-plus-content layout. Add a header that spans both columns with grid-column: span 2.

Challenge: Build a simple dashboard. Use a grid with a top header that spans the full width, a sidebar on the left, and a main area on the right split into a repeat(auto-fit, minmax(...)) grid of stat cards. Style the cards with a background, padding and border-radius, and use Flexbox inside each card to align a label and a number.

Quick quiz

Test yourself and earn XP

What makes CSS Grid different from Flexbox?

What does grid-template-columns: 1fr 1fr 1fr create?

What does the fr unit represent?

What does repeat(4, 1fr) mean?

How do you make one item span two columns?

FAQ

Use Grid when you need control in two dimensions at once β€” a page layout, a photo gallery, a dashboard with rows and columns. Use Flexbox for a single row or column, like a navbar or a toolbar. They work beautifully together: Grid for the overall page skeleton, Flexbox inside individual cells.

minmax(min, max) sets a track that is never smaller than 'min' and never larger than 'max'. Combined with auto-fill or auto-fit and repeat(), it lets a grid automatically add or remove columns as the screen resizes β€” a responsive grid with no media queries needed.