Cheatsheet

CSS Grid Cheatsheet

This cheatsheet is a lookup page for CSS Grid: the container and item properties, the track sizing functions, how line numbers and named areas work, and layouts you can paste. It is for developers who know what a grid is and need the exact syntax. The confusion it clears up is line numbering: lines are numbered, not cells, so a three-column grid has four column lines.

Quick reference

Container properties

Property Values Initial Does
`display` `grid`, `inline-grid` n/a Makes direct children grid items
`grid-template-columns` track list, `none`, `subgrid` `none` Defines explicit column tracks
`grid-template-rows` track list, `none`, `subgrid` `none` Defines explicit row tracks
`grid-template-areas` one string per row, or `none` `none` Names rectangular regions
`grid-template` rows / columns, or areas plus sizes `none` Shorthand for the three above
`grid-auto-rows` track size `auto` Size of rows created implicitly
`grid-auto-columns` track size `auto` Size of columns created implicitly
`grid-auto-flow` `row`, `column`, optionally `dense` `row` Fill direction for auto-placed items
`gap` one or two lengths `normal` Gutter between rows and columns
`justify-items` `start`, `end`, `center`, `stretch` `legacy` Aligns items inside cells on the inline axis
`align-items` `start`, `end`, `center`, `stretch`, `baseline` `normal` Aligns items inside cells on the block axis
`place-items` align then justify see parts Shorthand for both
`justify-content` `start`, `center`, `space-between`, `space-evenly` and more `normal` Places the whole grid when tracks are smaller than the container
`grid` template, or auto-flow forms `none` Shorthand that resets every grid property

Item properties

Property Values Initial Does
`grid-column` `start / end` lines `auto` Column placement
`grid-row` `start / end` lines `auto` Row placement
`grid-column-start`, `grid-column-end` line number, name, `span n` `auto` Longhands of `grid-column`
`grid-row-start`, `grid-row-end` line number, name, `span n` `auto` Longhands of `grid-row`
`grid-area` name, or `row-start / col-start / row-end / col-end` `auto` Places into a named area or four lines
`justify-self` `start`, `end`, `center`, `stretch` `auto` Aligns one item in its cell
`align-self` `start`, `end`, `center`, `stretch`, `baseline` `auto` Aligns one item in its cell
`order` integer `0` Changes auto-placement order

Track sizes

Value Meaning Measured example
`200px` Fixed length `200px` stays 200px
`1fr` One share of free space after fixed tracks and gaps See below
`auto` Fits content, and stretches to fill spare space Fits the 70px item
`min-content`, `max-content` Narrowest or widest the content can be Content dependent
`minmax(100px, 1fr)` Never below 100px, grows to its share Took 430px of 600px
`fit-content(300px)` Content size, capped at 300px Content dependent
`repeat(3, 1fr)` Three equal tracks See below
`repeat(auto-fill, minmax(200px, 1fr))` As many 200px-or-wider tracks as fit Three tracks in 600px

Computed grid-template-columns read from Chromium 153 in a 600px container:

You write Computed value
`200px 1fr 2fr` `200px 133.328px 266.672px`
`repeat(3, 1fr)` with `gap: 20px` `186.656px 186.672px 186.672px`
`100px minmax(100px, 1fr) auto` with a 70px third item `100px 430px 70px`
`repeat(auto-fill, minmax(200px, 1fr))` with 5 items `200px 200px 200px`

Line numbers

A grid with N columns has N + 1 column lines, numbered 1 to N + 1 from the start edge. Negative numbers count from the end, so -1 is the last line.

Line values Covers
`grid-column: 1 / 3` Columns 1 and 2
`grid-column: 2 / -1` From column 2 to the last column
`grid-column: span 2` Two tracks from the auto-placed start
`grid-column: 1 / -1` Every explicit column
`grid-area: 1 / 3 / -1` Row 1 to the last row line, starting at column line 3

Common patterns

Build a responsive card grid with no media queries

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

In a 600px container with five items, Chromium 153 created three 200px columns and two rows. Use it for galleries and product lists.

Lay out a page with named areas

.page {
  display: grid;
  grid-template-columns: 150px 1fr;
  grid-template-rows: 40px 100px 30px;
  grid-template-areas: "head head" "side main" "foot foot";
}
.h { grid-area: head; }
.s { grid-area: side; }
.m { grid-area: main; }
.f { grid-area: foot; }

Measured as x, y, width, height in a 600px container:

head  0,   0,   600, 40
side  0,   40,  150, 100
main  150, 40,  450, 100
foot  0,   140, 600, 30

Each string is one row, and repeating a name across cells makes the area span them. Every named area must be a rectangle.

Span columns and anchor to the last line

.g { display: grid; grid-template-columns: repeat(4, 1fr); }
.wide { grid-column: span 2; }
.tail { grid-column: 2 / -1; }

In a 600px container, the .wide item measured 300px wide. The .tail item started at x 150 and measured 450px wide, which is columns 2 to 4.

Fill gaps with dense packing

.g { display: grid; grid-template-columns: repeat(3, 100px); grid-auto-flow: dense; }
.w { grid-column: span 2; }

With items span-2, span-2 and a single cell, default flow put the third item at column 3 of row 2, which is x 200 and y 10. With dense, it moved back to the hole at column 3 of row 1, which is x 200 and y 0. Dense changes visual order, so avoid it when reading order matters.

Center one item in its cell

.g { display: grid; grid-template-columns: 200px; grid-template-rows: 100px; place-items: center; }

A 50px by 20px item landed at x 75 and y 40, which is the exact center of the 200px by 100px cell.

Size implicit rows

.g { display: grid; grid-template-columns: 100px 100px; grid-auto-rows: 30px; }

Five items produced three rows of 30px each. Without grid-auto-rows, rows created from overflow are auto.

Name lines for a centered content column

.layout {
  display: grid;
  grid-template-columns: [full-start] 1fr [content-start] minmax(0, 300px) [content-end] 1fr [full-end];
}
.text { grid-column: content; }
.bleed { grid-column: full; }

In a 600px container, .text measured x 150 and width 300, and .bleed measured x 0 and width 600. Naming the lines content-start and content-end lets grid-column: content select the span between them, so children never need to know the track numbers.

Check for subgrid support

console.log(CSS.supports('grid-template-columns', 'subgrid'));
console.log(CSS.supports('grid-template-rows', 'masonry'));

Output in Chromium 153:

true
false

Subgrid is part of Grid Level 2. The masonry value returned false in the same run, so do not rely on it.

Pitfalls

  • Counting cells instead of lines: grid-column: 1 / 3 covers two columns, not three. The end number is a line, so use span 2 if you think in cells.
  • Writing uneven or L-shaped named areas: names in grid-template-areas must form rectangles, and rows with different cell counts make the whole declaration invalid. Fix the strings so every row has the same number of cells.
  • Using the grid shorthand casually: grid resets the explicit tracks and the implicit grid properties together, while grid-template leaves the implicit ones alone. After grid-auto-rows: 25px, a later grid: auto-flow 40px / 1fr 1fr made grid-auto-rows compute to 40px in Chromium 153.
  • Expecting grid-gap in new code: Chromium 153 still reads grid-gap: 7px as an alias and reports 7px 7px for gap. Write gap, which is the standard name.
  • Using dense with content in reading order: grid-auto-flow: dense fills earlier holes, so DOM order and visual order differ. Keyboard focus follows the DOM.
  • Forgetting that fr only shares free space: 1fr takes what is left after fixed tracks and gaps, so in 200px 1fr 2fr at 600px the fr tracks are 133.328px and 266.672px, not 200px each.
  • Setting justify-content on a grid that fills its container: it does nothing when the tracks already use all the space. It matters for fixed-size tracks like repeat(3, 100px) in a wider box.
  • Relying on masonry: grid-template-rows: masonry returned false from CSS.supports in Chromium 153.

Related ZipKit tools

Related cheatsheets