Cheatsheet

Flexbox and Grid, side by side, with recipes

Both layout systems in one page: container properties, item properties, the full alignment matrix, the sizing keywords nobody remembers, and eight recipes you can paste straight into a stylesheet. Flexbox and Grid are listed next to each other on purpose, because the hard part is never the syntax - it is knowing which one to reach for.

Flexbox or Grid: decide in one sentence

Flexbox distributes items along one axis and lets content decide the sizes. Grid defines the sizes first, in two dimensions, and drops content into them. If you find yourself writing widths on flex children, you wanted Grid; if you find yourself writing a one-column grid, you wanted Flexbox.

You are building Reach for Why
A nav bar, toolbar, or button row flex One axis, items sized by their own content, spacing pushed with auto margins.
A page shell with header, sidebar, main, footer grid Two dimensions at once, and named areas make the markup order irrelevant.
A card grid that reflows on its own grid One line of auto-fit plus minmax replaces four media queries.
A form row where one field takes the slack flex flex: 1 on the field that should absorb leftover space.
Centering one thing in a box grid place-items: center is two words and handles both axes.
Rows that must line up across separate cards grid + subgrid Subgrid is the only way a child inherits the parent's tracks.

Flexbox container properties

Set these on the element that has display: flex. Defaults are called out because most flex bugs are a default you forgot about.

Property Values (default first) What it controls
display flex | inline-flex Makes children flex items. Inline-flex keeps the box itself inline.
flex-direction row | row-reverse | column | column-reverse Which way the main axis runs. Everything else is defined relative to this.
flex-wrap nowrap | wrap | wrap-reverse Whether items overflow on one line or break onto new lines.
flex-flow row nowrap Shorthand for direction plus wrap, in that order.
justify-content flex-start | center | flex-end | space-between | space-around | space-evenly Distribution of items along the MAIN axis, once they are sized.
align-items stretch | flex-start | center | flex-end | baseline Position of every item on the CROSS axis. Stretch is why unequal cards match height.
align-content normal | flex-start | center | space-between | stretch Spacing BETWEEN wrapped lines. Does nothing without flex-wrap: wrap.
gap normal | length | row-gap column-gap Space between items without margin hacks. Works in Flexbox everywhere now.
row-gap normal | length Gutter between wrapped lines only.
column-gap normal | length Gutter between items on the same line only.
place-content align-content justify-content Shorthand. One value sets both.

Gotcha: justify-items does nothing in Flexbox. There is no such thing as per-item main-axis alignment - use an auto margin instead.

Flexbox item properties

Set these on the children. The flex shorthand is worth memorizing because the longhand defaults are counterintuitive.

Property Default What it does
flex-grow 0 Share of LEFTOVER space this item absorbs, as a ratio against its siblings.
flex-shrink 1 Share of OVERFLOW this item gives up. Set 0 to keep a sidebar from squashing.
flex-basis auto Starting size on the main axis before grow and shrink run. Beats width.
flex: 1 1 1 0% Equal columns regardless of content, because the basis is zero.
flex: auto 1 1 auto Grows and shrinks, but starts from content size. Wider text gets a wider column.
flex: none 0 0 auto Fully rigid. The correct value for an icon or a fixed-width control.
flex: 0 0 280px - A sidebar that is exactly 280px and refuses to move.
align-self auto Overrides the container's align-items for this one item.
order 0 Visual reordering only. Tab order and screen readers still follow the DOM.
margin-left: auto - Eats all leftover space to the left, pushing this item and the rest right.
margin: auto - Centers a single item on both axes with no container properties at all.
min-width: 0 - The fix for a flex child that refuses to shrink and blows out the row.

Gotcha: a flex item's automatic minimum size is its content size, not zero. That is why one long unbroken string or a wide table can push a row past its container. min-width: 0 on the flex child (and overflow: hidden if it holds text) is the fix, every time.

Grid container properties

Property Example What it does
display grid Turns children into grid items. inline-grid keeps the box inline.
grid-template-columns 200px 1fr 200px Defines the explicit column tracks. Any length, percentage, fr, or function.
grid-template-rows auto 1fr auto Explicit row tracks. The classic header, body, footer shell.
grid-template-areas "nav main" Names regions with an ASCII picture. Rearranging is a one-line media query.
grid-auto-columns minmax(120px, 1fr) Size of columns created implicitly, beyond the template.
grid-auto-rows minmax(80px, auto) Size of implicit rows. The usual home for a minimum row height.
grid-auto-flow row | column | dense Direction auto-placement fills. dense backfills holes left by spans.
gap 1rem 2rem Row gap then column gap. Gaps are never added to the outside edges.
justify-items stretch | start | center | end How every item sits INSIDE its own cell, horizontally.
align-items stretch | start | center | end Same thing vertically.
justify-content start | center | space-between Where the WHOLE grid sits when the tracks are narrower than the container.
align-content start | center | space-between Same for the block axis, when rows do not fill the height.
place-items center align-items then justify-items. One value applies to both.
grid-template rows / columns Shorthand for rows, columns, and areas in one declaration.

Grid item placement

Grid lines are numbered from 1, and negative numbers count back from the end. That is why 1 / -1 means "full width" no matter how many columns exist.

Declaration What it does
grid-column: 2 / 4 Starts at line 2 and ends at line 4, covering two columns.
grid-column: span 2 Two columns wide wherever auto-placement puts it.
grid-column: 1 / -1 Full width of the explicit grid. The full-bleed row inside a card grid.
grid-row: 1 / span 3 Starts on row line 1 and covers three rows.
grid-area: sidebar Drops the item into the named region from grid-template-areas.
grid-area: 1 / 1 / 3 / 4 Row-start, column-start, row-end, column-end in one shot.
grid-column: content-start / content-end Named lines. Any area name automatically creates -start and -end lines.
justify-self: end Pushes this one item to the right edge of its cell.
align-self: center Vertically centers this one item in its cell.
place-self: center end align-self then justify-self, in one declaration.
grid-template-columns: subgrid On a grid item that is itself a grid: inherit the parent's tracks so nested content lines up.

Gotcha: -1 refers to the last line of the EXPLICIT grid only. If items were auto-placed into implicit tracks, 1 / -1 stops short of them.

Every alignment property in one matrix

The single most useful rule: in Grid, justify-* is always the inline (column) axis and align-* is always the block (row) axis. In Flexbox they swap meaning when flex-direction is column. Every place-* shorthand takes align first, justify second.

Property In Flexbox In Grid
justify-content Items along the main axis. The whole column track set inside the container.
align-content Wrapped lines. No effect without wrapping. The whole row track set inside the container.
justify-items Ignored. Every item inside its own cell, horizontally.
align-items Every item on the cross axis. Every item inside its own cell, vertically.
justify-self Ignored. Use an auto margin. One item inside its cell, horizontally.
align-self One item on the cross axis. One item inside its cell, vertically.
place-content align-content justify-content. align-content justify-content.
place-items Only the align half applies. align-items justify-items. place-items: center is the centering one-liner.
place-self Only the align half applies. align-self justify-self.

Alignment values and what they actually do

Value Behavior
start / end Writing-mode aware edges. Prefer these over left and right.
flex-start / flex-end The Flexbox spellings. Identical to start and end in practice.
center Centers along that axis. Leftover space splits evenly on both sides.
stretch Fills the cross axis. Only works when the item has no fixed size on that axis.
baseline Lines up the first line of text across items of different sizes.
space-between First item flush left, last flush right, equal gaps between.
space-around Equal space around each item, so edge gaps are half the inner gaps.
space-evenly Every gap identical, including the two edges. Usually the one you meant.
safe center Centers, but falls back to start rather than overflowing off-screen.

Sizing: fr, minmax, auto-fit, and auto-fill

These are the track functions that make a grid responsive without a single media query.

Value What it means
1fr One share of the FREE space left after fixed tracks and gaps are subtracted.
2fr 1fr Two-to-one split of the free space, not of the container width.
minmax(200px, 1fr) Never narrower than 200px, otherwise takes a share of the free space.
minmax(0, 1fr) The overflow fix. Plain 1fr is minmax(auto, 1fr) and will not shrink below content.
repeat(3, 1fr) Three equal columns. Expands to 1fr 1fr 1fr.
repeat(auto-fit, minmax(240px, 1fr)) As many columns as fit; leftover EMPTY tracks collapse, so items stretch to fill.
repeat(auto-fill, minmax(240px, 1fr)) Same, but empty tracks are KEPT, so three items in a five-column row stay narrow.
min-content As narrow as the longest unbreakable word.
max-content As wide as the content wants with no wrapping at all.
fit-content(300px) max-content, clamped at 300px. A caption column that never gets silly.
auto Content-sized, but stretches to absorb free space when no fr track exists.
clamp(16rem, 40%, 32rem) Valid as a track size. Fluid width with a floor and a ceiling.
aspect-ratio: 16 / 9 On the item, not the track. Keeps cells proportional as columns reflow.
[full-start] 1fr [content-start] Named grid lines in brackets, for readable full-bleed layouts.

Gotcha: auto-fit and auto-fill look identical until the row is not full. With four cards in a container wide enough for six, auto-fill leaves two empty slots and keeps the cards narrow; auto-fit collapses them and the four cards spread out. Pick deliberately.

Copy-paste layout recipes

Eight layouts that cover most of what a real page needs. All of them are modern CSS with no floats, no clearfix, and no positioning hacks.

Dead center, both axes

/* Grid: shortest version that exists */
.center { display: grid; place-items: center; min-block-size: 100dvh; }

/* Flexbox equivalent */
.center { display: flex; justify-content: center; align-items: center; }

/* No container properties at all: auto margins on the child */
.center > * { margin: auto; }

Holy grail: header, sidebar, main, aside, footer

.shell {
  display: grid;
  min-block-size: 100dvh;
  gap: 1rem;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: 14rem minmax(0, 1fr) 12rem;
  grid-template-areas:
    "head head  head"
    "nav  main  aside"
    "foot foot  foot";
}
.shell > header { grid-area: head; }
.shell > nav    { grid-area: nav; }
.shell > main   { grid-area: main; }
.shell > aside  { grid-area: aside; }
.shell > footer { grid-area: foot; }

@media (width < 60rem) {
  .shell {
    grid-template-columns: 1fr;
    grid-template-areas: "head" "nav" "main" "aside" "foot";
  }
}

The minmax(0, 1fr) on the main column is not decoration. Without it, a wide table or a long code block inside main pushes the whole layout sideways.

Sidebar that collapses without a media query

.with-sidebar {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}
.with-sidebar > .side { flex: 1 1 16rem; }   /* ideal width, may grow */
.with-sidebar > .body { flex: 999 1 60%; }   /* hogs space until 60% is impossible */

The huge grow factor on the body means the sidebar only wraps when the body can no longer hold its 60% basis. Container queries do this more explicitly, but this version works in one declaration.

Responsive card grid, zero breakpoints

.cards {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
}
.cards > .featured { grid-column: 1 / -1; }  /* one full-width hero card */

The min(18rem, 100%) wrapper is what stops the grid overflowing on a 320px phone, where a hard 18rem minimum would be wider than the viewport.

Sticky footer that stays down on short pages

body {
  min-block-size: 100dvh;
  display: grid;
  grid-template-rows: auto 1fr auto;
}
/* header, main, footer in source order - nothing else needed */

Nav bar with a group pushed to the right

.nav {
  display: flex;
  align-items: center;
  gap: 1rem;
}
.nav > .logo   { flex: none; }
.nav > .spacer { margin-inline-start: auto; }  /* everything after this goes right */

Auto margins beat space-between here because they work with any number of items on either side.

Media object: fixed avatar, fluid text

.media {
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr);
  gap: 0.75rem;
  align-items: start;
}
/* Long words in the text column now wrap instead of overflowing */

Full-bleed row inside a constrained article

.article {
  display: grid;
  grid-template-columns:
    [full-start] minmax(1rem, 1fr)
    [content-start] min(70ch, 100%) [content-end]
    minmax(1rem, 1fr) [full-end];
}
.article > *          { grid-column: content; }
.article > .full-bleed { grid-column: full; }

Because area names generate -start and -end lines, grid-column: content is shorthand for content-start / content-end.

Gotchas that cost people an afternoon

Symptom Cause and fix
A flex or grid child overflows its container Automatic minimum size is content-based. Add min-width: 0 to the child, or use minmax(0, 1fr) for the track.
align-content does nothing In Flexbox it only applies to multiple lines. Add flex-wrap: wrap.
Percentage heights collapse A percentage height needs a resolved parent height. Use 1fr in a grid row or 100dvh at the root.
gap is added around the outside It is not. If there is edge space, it is padding on the container or a stray margin on a child.
Images stretch in a flex row Default align-items: stretch. Use align-self: start plus object-fit: contain.
Tab order does not match what I see order and grid placement do not change the DOM. Reorder the markup instead.
A grid row is taller than its content Items stretch by default. Set align-items: start on the container.
Nested card contents will not line up Each card is its own grid. Use grid-template-rows: subgrid on the card so it borrows the parent's rows.

Keep going

Writing these as utility classes instead of stylesheets? The Tailwind CSS cheatsheet maps every property here to its utility, including the grid track and alignment utilities that are easy to guess wrong.

Still choosing an approach rather than writing one, the CSS and styling tool guide covers frameworks, component libraries, and design tokens, and Tailwind vs CSS Modules settles the authoring question with a verdict.

Specs worth bookmarking: MDN on Flexbox and MDN on Grid. More quick references live in the cheatsheet index.