Skip to content
Free Tool Arena

How-To & Life · Guide · Developer Utilities

How to Use CSS Grid

grid-template-columns/rows, fr units, grid-area, minmax, auto-fill vs auto-fit, responsive grids, and when to grid vs flex.

Updated April 2026 · 6 min read

CSS Grid is the first layout system in the browser that was actually designed for two-dimensional layout. Rows and columns are first-class citizens, track sizing has a dedicated unit (the fr), and you can describe a whole page in about ten lines without a single wrapper div. Grid is strictly more capable than flexbox for anything that needs to align across both axes, but it’s also more verbose for simple one-axis jobs. This guide covers the properties you’ll actually use, the tricks (auto-fill, minmax, named areas) that make grid shine, and the rule of thumb for when grid is the right tool.

Advertisement

The grid mental model

A grid container defines tracks — rows and columns — and grid items fall into cells at their intersections. You can describe tracks explicitly (grid-template-columns) or let the browser create them implicitly as items arrive. Everything else is: pick which cells an item occupies.

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 16px;
}

Three equal columns, 16px gap, done. No media queries, no wrappers.

The fr unit

fr stands for “fraction of remaining space.” After fixed-size tracks are allocated, the remaining space is divided among thefr tracks in proportion.

grid-template-columns: 200px 1fr 1fr;
/* 200px sidebar, two equal flexible columns */

grid-template-columns: 1fr 3fr;
/* main column is 3x the sidebar */

fr is what makes grid feel fluid. Percentages also work but don’t account for gaps, so they often cause overflow. Prefer fr.

grid-template-columns and grid-template-rows

Values can mix fixed sizes, fr units, auto, and functions:

grid-template-columns: 240px 1fr;        /* sidebar + main */
grid-template-columns: repeat(4, 1fr);   /* four equal */
grid-template-columns: 1fr 2fr 1fr;      /* weighted */
grid-template-rows: auto 1fr auto;       /* header, main, footer */

repeat(n, ...) is syntactic sugar for repetitive tracks. auto sizes to content. The classic “sticky footer” layout is just grid-template-rows: auto 1fr auto on a body with min-height: 100vh.

minmax for responsive tracks

minmax(a, b) sets a minimum and a maximum size for a track. It’s how you keep columns from collapsing too small or stretching too wide.

grid-template-columns: repeat(3, minmax(200px, 1fr));
/* three columns, each at least 200px */

auto-fill vs auto-fit

Combine repeat with auto-fill or auto-fit to get cards that rewrap themselves as the viewport changes — no breakpoints.

/* auto-fill: empty columns are kept as invisible tracks */
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));

/* auto-fit: empty columns collapse, remaining items stretch */
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));

Rule of thumb: auto-fit if you want cards to stretch to fill the row even when few; auto-fill if you want them to stay a consistent size and leave empty space on the right.

grid-column and grid-row on items

Place an item across multiple tracks with grid-column or grid-row:

.hero  { grid-column: 1 / -1; }          /* full width */
.card  { grid-column: span 2; }          /* two columns wide */
.photo { grid-row: 1 / 3; grid-column: 2 / 4; }

Line numbers are 1-based. -1 means the last line. The span N shorthand says “start wherever I land, take N tracks.”

Named grid areas

For page-level layouts, grid-template-areas is the most readable option — you literally draw the layout in ASCII.

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

Changing the layout on mobile becomes a matter of rewriting the template inside a media query — no DOM restructuring required.

Responsive grids without media queries

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

Ten cards? Four rows of three plus a row of two at desktop, two columns at tablet, one column on phone. All from one rule. This pattern alone replaces most of the grid-system CSS that frameworks used to ship.

Grid items alignment

Grid has two layers of alignment: the container aligns tracks (justify-content, align-content), and each cell aligns its content (justify-items, align-items, or per-item justify-self, align-self).

.grid {
  justify-content: center;   /* tracks themselves centered */
  align-items: center;       /* item content centered in its cell */
}

Same keywords as flexbox, same mental model — just applied to grid cells rather than a flex line.

Grid vs Flexbox

One axis? Flexbox. Nav bars, toolbars, sidebars of stacked items. The browser decides where items wrap.

Two axes that must line up? Grid. Dashboards, photo galleries with aligned rows, full-page layouts. You decide the tracks.

They nest happily — grid for the shell, flex inside each cell. Don’t pick one as your religion.

Gaps and alignment

gap (formerly grid-gap) sets spacing between tracks. Always use it — it handles wrapping correctly and avoids the trailing-item margin problem.

.grid {
  gap: 16px;        /* same for rows and columns */
  gap: 24px 16px;   /* 24px row-gap, 16px column-gap */
}

Implicit tracks

If items run out of explicit tracks, the grid creates new ones automatically. Control their size with grid-auto-rows and grid-auto-columns.

.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 200px;
}

Common mistakes

Using percentages instead of fr. 33.33% doesn’t account for gaps and causes overflow. 1fr does the math correctly.

Reaching for flex when rows need to align. If two cards in the same row have different heights and you want them equal, grid is the cleaner answer.

Forgetting to set min-width: 0 on items with overflow. Grid items default to min-width: auto and can refuse to shrink below their content width. Set min-width: 0 if a long word is breaking your layout.

Hard-coding breakpoints that auto-fit would handle. repeat(auto-fit, minmax(X, 1fr)) replaces a lot of media queries.

Confusing auto-fit and auto-fill. They behave identically until there are fewer items than tracks. Then auto-fit stretches items to fill; auto-fill leaves gaps.

Naming every grid line. Start simple; only name lines once the layout gets complex enough to benefit.

Run the numbers

Scaffold a grid visually with the grid layout generator. For one-dimensional rows inside each grid cell, drop into the flexbox playground, and round off your card corners with the border radius generator so the grid reads as one cohesive surface.

Advertisement

Found this useful?Email