Grid Container and Defining Tracks

โ–ถ Try It Yourself

CSS Grid is a two-dimensional layout system โ€” the first native CSS tool that lets you control rows and columns simultaneously. While Flexbox excels at one-dimensional layouts (a row of buttons, a stacked column), Grid is designed for two-dimensional structures: page layouts, dashboards, photo galleries, and any UI that has both rows and columns. In this lesson you will learn how to activate a grid container, define column and row tracks, and understand the fr unit that makes Grid uniquely powerful.

Grid Fundamentals

Term Definition CSS Property
Grid container The parent element with display: grid display: grid or display: inline-grid
Grid items Direct children of the grid container Automatic โ€” no extra property needed
Grid lines The dividing lines between rows and columns โ€” numbered from 1 Referenced by grid-column, grid-row
Grid tracks The columns and rows themselves โ€” space between two lines grid-template-columns, grid-template-rows
Grid cell The intersection of a row track and a column track Items placed in cells by default
Grid area One or more cells combined โ€” a rectangular region grid-area, grid-template-areas

Defining Columns and Rows

Syntax Result Example
200px 200px 200px Three fixed 200px columns grid-template-columns: 200px 200px 200px
repeat(3, 1fr) Three equal fluid columns grid-template-columns: repeat(3, 1fr)
1fr 2fr 1fr Side columns half the width of centre grid-template-columns: 1fr 2fr 1fr
repeat(3, 200px) Shorthand for three 200px columns grid-template-columns: repeat(3, 200px)
auto-fill with minmax Responsive โ€” as many columns as fit repeat(auto-fill, minmax(200px, 1fr))

The fr Unit

Value Meaning Compared to Flexbox
1fr 1 fraction of the available free space after fixed tracks are placed Like flex: 1 but for grid tracks
2fr Twice as much free space as 1fr columns Like flex: 2
minmax(200px, 1fr) At least 200px, grows to fill free space No direct Flexbox equivalent
min-content Track is as narrow as the widest single word Like flex-basis: min-content
max-content Track is as wide as the widest single-line content Like flex-basis: max-content
Note: The fr unit distributes free space โ€” what remains after fixed, auto, and min-content tracks are sized. This means 1fr 200px 1fr first reserves 200px for the middle column, then splits whatever space is left equally between the two fr columns โ€” far more predictable than percentages.
Tip: repeat(auto-fill, minmax(250px, 1fr)) is one of the most powerful single lines in CSS. It creates as many columns as will fit at 250px minimum width, stretches them to fill the row, and automatically wraps to a new row โ€” a fully responsive grid with no media queries needed.
Warning: Unlike Flexbox where gap is a relatively new addition, CSS Grid had gap (originally grid-gap) from the beginning. Always use gap (not margins) for spacing between grid items โ€” it applies only between tracks, never on the outer edges, and works in both row and column directions.

Basic Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Grid Container and Tracks</title>
  <style>
    *, *::before, *::after { box-sizing: border-box; }
    body { font-family: system-ui, sans-serif; padding: 32px; background: #f8fafc; }
    h3   { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em;
           color: #64748b; margin: 24px 0 8px; }

    /* โ”€โ”€ Three equal columns with fr โ”€โ”€ */
    .grid-equal {
      display: grid;
      grid-template-columns: repeat(3, 1fr); /* 3 equal columns */
      gap: 12px;
      margin-bottom: 24px;
    }

    /* โ”€โ”€ Mixed fixed + fluid columns โ”€โ”€ */
    .grid-mixed {
      display: grid;
      grid-template-columns: 180px 1fr 2fr; /* fixed | fluid | double fluid */
      gap: 12px;
      margin-bottom: 24px;
    }

    /* โ”€โ”€ Explicit rows + columns โ”€โ”€ */
    .grid-explicit {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      grid-template-rows: 60px 120px;   /* row 1: 60px, row 2: 120px */
      gap: 12px;
      margin-bottom: 24px;
    }

    /* โ”€โ”€ Auto-responsive grid โ€” no media queries โ”€โ”€ */
    .grid-auto {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
      gap: 12px;
    }

    /* Shared item style */
    .item {
      background: #4f46e5;
      color: white;
      border-radius: 8px;
      padding: 16px;
      font-size: 0.8rem;
      font-weight: 600;
      display: flex;
      align-items: center;
      justify-content: center;
      text-align: center;
    }
    .item:nth-child(2n) { background: #7c3aed; }
    .item:nth-child(3n) { background: #0891b2; }
  </style>
</head>
<body>

  <h3>repeat(3, 1fr) โ€” three equal columns</h3>
  <div class="grid-equal">
    <div class="item">1fr</div>
    <div class="item">1fr</div>
    <div class="item">1fr</div>
  </div>

  <h3>180px 1fr 2fr โ€” fixed | fluid | double</h3>
  <div class="grid-mixed">
    <div class="item">180px (fixed)</div>
    <div class="item">1fr</div>
    <div class="item">2fr (double)</div>
  </div>

  <h3>Explicit rows: 60px then 120px</h3>
  <div class="grid-explicit">
    <div class="item">60px</div>
    <div class="item">60px</div>
    <div class="item">60px</div>
    <div class="item">60px</div>
    <div class="item">120px</div>
    <div class="item">120px</div>
    <div class="item">120px</div>
    <div class="item">120px</div>
  </div>

  <h3>auto-fill minmax(160px, 1fr) โ€” resize window!</h3>
  <div class="grid-auto">
    <div class="item">A</div>
    <div class="item">B</div>
    <div class="item">C</div>
    <div class="item">D</div>
    <div class="item">E</div>
    <div class="item">F</div>
  </div>

</body>
</html>

How It Works

Step 1 โ€” display: grid Activates the Grid Context

Adding display: grid to a parent makes all direct children grid items. Unlike Flexbox, a grid does nothing visually until you define columns โ€” items stack in a single column by default (the browser creates one implicit column track per item).

Step 2 โ€” repeat(3, 1fr) Divides Space Equally

The browser calculates total container width, subtracts gap space (2 gaps of 12px = 24px), then divides the remainder equally among 3 fr columns. At 900px container: (900 – 24) / 3 = 292px per column. Resize the window and all three columns resize together.

Step 3 โ€” Mixed Tracks Size in Order

In 180px 1fr 2fr, the browser first reserves 180px for column 1 and the two gaps (24px total), then distributes the remaining space: 1fr gets one share, 2fr gets two shares. At 900px: remaining = 900 – 180 – 24 = 696px; 1fr = 232px; 2fr = 464px.

Step 4 โ€” grid-template-rows Sets Explicit Row Heights

grid-template-rows: 60px 120px gives the first row a fixed 60px height and the second row 120px. Items in row 1 are sized to the track โ€” they stretch to fill 60px. Additional rows beyond the defined tracks use the browser’s implicit row sizing (auto).

Step 5 โ€” auto-fill + minmax Creates Responsive Columns Automatically

repeat(auto-fill, minmax(160px, 1fr)) tells the browser to fill the row with as many 160px+ columns as will fit. On a 700px container: 4 columns fit (4 ร— 160 + 3 ร— 12 = 676px); on 400px: 2 columns fit. Each column stretches to 1fr to fill the row. Zero media queries required.

Real-World Example: Dashboard Metrics Grid

/* dashboard-grid.css */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #f1f5f9; padding: 32px; }

/* โ”€โ”€ Outer page layout: sidebar + main โ”€โ”€ */
.dashboard {
  display: grid;
  grid-template-columns: 240px 1fr;  /* fixed sidebar, fluid main */
  grid-template-rows: auto 1fr auto;  /* header, content, footer */
  min-height: 100vh;
  gap: 0;
}

/* โ”€โ”€ Stat cards: auto-responsive โ”€โ”€ */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}

.stat-card {
  background: white;
  border-radius: 12px;
  padding: 20px 24px;
  border: 1px solid #e2e8f0;
  box-shadow: 0 1px 4px rgba(0,0,0,0.04);
}
.stat-label { font-size: 0.75rem; font-weight: 700; text-transform: uppercase;
              letter-spacing: 0.06em; color: #64748b; margin-bottom: 8px; }
.stat-value { font-size: 2rem; font-weight: 800; color: #0f172a; line-height: 1; }
.stat-delta { font-size: 0.8rem; font-weight: 600; margin-top: 6px; }
.delta-up   { color: #10b981; }
.delta-down { color: #ef4444; }

/* โ”€โ”€ Chart area: 2 wide + 1 narrow โ”€โ”€ */
.charts-grid {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 16px;
  margin-bottom: 24px;
}

.chart-card {
  background: white;
  border-radius: 12px;
  padding: 24px;
  border: 1px solid #e2e8f0;
  min-height: 260px;
}

Common Mistakes

Mistake 1 โ€” Using percentages instead of fr for equal columns

โŒ Wrong โ€” percentages do not account for gap, causing overflow:

.grid { display: grid; grid-template-columns: 33.33% 33.33% 33.33%; gap: 16px; }
/* Total = 100% + 2 x 16px gap = overflow! */

โœ… Correct โ€” fr automatically deducts gap before distributing space:

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

Mistake 2 โ€” Confusing auto-fill with auto-fit

โŒ Wrong โ€” auto-fit collapses empty tracks, stretching remaining items unexpectedly:

.grid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
/* With 2 items in a 900px container: each item becomes 450px */

โœ… Correct โ€” auto-fill keeps empty track slots, items stay at minmax size:

.grid { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
/* With 2 items in a 900px container: items are 200px, rest is empty */

Mistake 3 โ€” Setting gap on items instead of the container

โŒ Wrong โ€” margin on items creates uneven outer spacing:

.grid { display: grid; grid-template-columns: repeat(3, 1fr); }
.item { margin: 8px; } /* adds gaps AND outer spacing โ€” uneven edges */

โœ… Correct โ€” gap on the container, no margin on items:

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

▶ Try It Yourself

Quick Reference

Property Example Result
display: grid display: grid Activates grid on container
grid-template-columns repeat(3, 1fr) 3 equal columns
grid-template-rows 80px auto Fixed header, auto body
gap gap: 16px Between-track spacing only
fr 1fr 2fr Fractional free space โ€” after fixed tracks
minmax(min, max) minmax(200px, 1fr) At least 200px, grows to 1fr
repeat(auto-fill, ...) repeat(auto-fill, minmax(200px, 1fr)) Responsive โ€” as many columns as fit

🧠 Test Yourself

A grid container is 960px wide with grid-template-columns: 200px 1fr 2fr and gap: 20px. How wide is the 1fr column?





โ–ถ Try It Yourself