Grid

Lay out in two dimensions: define tracks, place items, and let the grid respond on its own.

10of 26
≈ 14Min read
10Parts

Two axes at once

Flexbox lays things along one axis and wraps when it runs out. Grid defines a structure — rows and columns — and places items into it. When the alignment has to hold in both directions, grid is the tool.

three equal columns
.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 20px;
}

fr

fr is a share of the space left over after gaps and fixed tracks are taken out. 1fr 2fr gives the second track twice the leftover. It only exists in grid track sizing.

a sidebar and a main column
.layout {
  display: grid;
  grid-template-columns: 260px 1fr;   /* fixed, then everything else */
  gap: 32px;
}
fr has a minimum

1fr is really minmax(auto, 1fr), so a track will not shrink below its content — one long word or a wide table blows the layout out. Write minmax(0, 1fr) when the content might be wide.

repeat, minmax, auto-fit

Those four lines replace a stack of breakpoints. With two cards, auto-fit gives two wide ones; auto-fill gives two narrow ones and empty space.

  • repeat(3, 1fr) — three equal tracks.
  • minmax(240px, 1fr) — at least 240, otherwise a share of the space.
  • auto-fill — make as many tracks as fit, leaving empty ones.
  • auto-fit — the same, then collapse the empty ones so the items stretch.
the responsive grid, with no media query at all
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 20px;
}

Rows

Tracks you define are the explicit grid. Items that go past it create implicit tracks, sized by grid-auto-rows or grid-auto-columns.

explicit and implicit
.grid {
  display: grid;
  grid-template-rows: auto 1fr auto;   /* header, body, footer */
  grid-auto-rows: minmax(120px, auto); /* any row beyond the template */
  min-height: 100svh;
}

Placing an item

Grid lines are numbered from 1, and negative numbers count from the end. 1 / -1 is the one to remember: full width, however many columns there turn out to be.

lines, not tracks
.feature {
  grid-column: 1 / 3;        /* from line 1 to line 3 — two columns */
  grid-column: span 2;       /* two columns, wherever it lands */
  grid-column: 1 / -1;       /* the whole width, whatever the count */
  grid-row: 2 / 4;
}

Named areas

The rearrangement at the breakpoint is four words. Note that side moves below main visually while staying before it in the DOM — the same caveat as flex order applies, so use it only where the reading order still makes sense.

a layout you can read
.page {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "head head"
    "side main"
    "foot foot";
  min-height: 100svh;
  gap: 24px;
}

.page > header { grid-area: head; }
.page > aside  { grid-area: side; }
.page > main   { grid-area: main; }
.page > footer { grid-area: foot; }

@media (max-width: 720px) {
  .page {
    grid-template-columns: 1fr;
    grid-template-areas: "head" "main" "side" "foot";
  }
}

Alignment

the shortest centring in CSS
.centre {
  display: grid;
  place-items: center;
  min-height: 100svh;
}
PropertyAligns
justify-items / justify-selfItems within their cell, along the inline (row) axis.
align-items / align-selfItems within their cell, along the block (column) axis.
justify-contentThe whole grid in the container, horizontally — when the tracks do not fill it.
align-contentThe whole grid vertically.
place-items: centerShorthand for both item axes.

Overlap

Two grid items placed in the same cell overlap, in DOM order, and z-index orders them. That makes grid the cleanest way to stack things — a caption over an image, a gradient over a video — without position: absolute and its guesswork.

a caption over a picture
.hero {
  display: grid;
}

.hero > * {
  grid-area: 1 / 1;       /* everything in the same cell */
}

.hero .caption {
  align-self: end;
  z-index: 1;
}

Subgrid

subgrid lets a child use its parent's tracks instead of its own. It solves the problem cards have had forever: three cards whose titles, text and buttons all line up with each other, however long the text is.

rows that line up across cards
.deck {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  grid-template-rows: auto 1fr auto;
  gap: 20px;
}

.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;   /* take the deck's three rows */
}

Grid or flex?

  • Grid when you know the structure: a page layout, a card deck, a form with labels and fields aligned, anything where both axes matter.
  • Flex when the content decides: a row of buttons, a toolbar, a tag list, anything that is "line these up and share the space".
  • They nest happily. A grid of cards, each of which is a flex column, is the most common combination there is.

Practice