CSS flexbox: laying out a row without fighting it

Flexbox is for one line of things: a label, a bar that takes the remaining space, a number on the right, all vertically centred with a gap between them. Four patterns cover almost every row, and one trap, children that refuse to shrink, explains most of the overflow bugs.

CSS flexbox arranges the children of an element along a single line, horizontal or vertical, and decides how they share the space: which ones keep their size, which one absorbs what is left, how they line up, and what goes between them.

The markup. The highlighted line is the part this term is about.
The markup. The highlighted line is the part this term is about.

It is the right tool for a row and the wrong tool for a grid of cards, which is what CSS grid is for.

This guide covers the four patterns that handle most rows, the shrinking trap that causes overflow on phones, alignment, and how flexbox and grid divide the work on a typical page.

.bar {
  display: flex;
  align-items: center;
  gap: 14px;
}

Items sit in a row, vertically centred, with even spacing. Three lines, and it replaces every float and vertical-centring trick that came before it.

The four flexbox patterns

A toolbar with something pushed right

Flexbox arranges children along one line and decides how they share the space. It is the tool for a row: label, flexible middle, fixed value, vertically centred, with a gap between them.
Flexbox arranges children along one line and decides how they share the space. It is the tool for a row: label, flexible middle, fixed value, vertically centred, with a gap between them.
.bar { display: flex; align-items: center; gap: 14px; }
.bar .right { margin-left: auto; }

margin-left: auto absorbs all remaining space, pushing that item and everything after it to the right. Cleaner than justify-content: space-between, which only works when there are exactly two groups.

Equal columns

.cols { display: flex; gap: 16px; }
.cols > * { flex: 1; min-width: 0; }

flex: 1 is shorthand for "grow, shrink, and start from zero" — so every child takes an equal share regardless of its content. The min-width: 0 is explained below and is not optional.

A sidebar that does not shrink

.layout { display: flex; gap: 20px; }
.side { flex: 0 0 220px; }   /* never grow, never shrink, 220px */
.main { flex: 1; min-width: 0; }

For a page-level layout, grid with grid-template-columns: 220px 1fr says the same thing more directly.

Wrapping chips

.chips { display: flex; flex-wrap: wrap; gap: 6px; }

flex-wrap: wrap is what stops a row of tags overflowing on a phone. Its absence is a routine cause of sideways scrolling.

A screenshot of the page ✗ Text is not selectable ✗ Numbers cannot be copied ✗ Charts stop being interactive ✗ Goes stale the moment data changes The live page ✓ Text selects and copies ✓ Tables can be read by tools ✓ Charts still respond to hover ✓ Update the source, link is current
A row that reflows on a phone is read. One whose children refuse to shrink scrolls sideways.

The shrinking trap

This is the one that costs people an afternoon.

A flex item will not shrink below the size of its content. So a long URL, a long word or a wide table inside a flex item pushes the item wider than its share, and the row overflows.

/* broken: the text refuses to shrink */
.item { flex: 1; }

/* fixed */
.item { flex: 1; min-width: 0; }

Truncation depends on it too:

.title {
  min-width: 0;              /* without this, nothing below works */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Rule: any flex item containing text gets min-width: 0.

Alignment, concisely

.box {
  display: flex;
  justify-content: center;   /* along the main axis */
  align-items: center;       /* across it */
}
Property Axis Common values
justify-content Main (the row, by default) flex-start, center, space-between
align-items Cross (down the row) center, flex-start, stretch, baseline

align-items: baseline is the underused one — it lines text up on its baseline rather than its box, which is what you want when a large number sits next to a small label.

Centring something both ways:

.center { display: grid; place-items: center; }

Grid does it in two words. Use it.

Flexbox or grid

Situation Use
A toolbar, a button row, a row of chips Flexbox
A card's internal stack Flexbox, flex-direction: column
Equal columns whose content varies Either — grid is less fiddly
A card grid that reflows Grid
Page layout Grid
One item pushed to the far end Flexbox with margin-left: auto

The short version: flexbox distributes items along a line; grid defines the shape of a container. If you are describing the container, use grid.

The five things that go wrong

Symptom Cause Fix
Text overflows its item Items will not shrink below content min-width: 0 on the item
Truncation does nothing Same min-width: 0, then text-overflow
A row of chips overflows No wrapping flex-wrap: wrap
A sidebar collapses flex: 1 on it too flex: 0 0 220px
Uneven spacing at the edges Margins instead of gap gap on the container

The first two are the same cause and account for most flexbox debugging. A flex item's default minimum size is its content, which is reasonable and is almost never what you want for text.

Where grid is the better answer

/* centring, both axes */
.center { display: grid; place-items: center; }

/* a page layout */
.layout { display: grid; grid-template-columns: 220px 1fr; gap: 20px; }

/* cards that reflow with no media query */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 10px; }

All three are shorter and less fragile in grid than in flexbox. Keep flexbox for rows of items — toolbars, button groups, a card's internal stack — and reach for grid when you are describing the container's shape. For the responsive behaviour specifically, the auto-fitting grid replaces a set of media queries entirely.

Three flexbox mistakes that cost the most

Forgetting min-width: 0. A flex child with long text refuses to shrink below the text's natural width, so the row overflows on a phone. min-width: 0 on the flexible child lets it shrink and wrap.

Using flex for a grid of cards. flex-wrap will wrap cards, but the last row stretches to fill or leaves awkward gaps, and every card needs a width. CSS grid with auto-fit does the job in one line.

Centring with margins. align-items: center and justify-content: center centre a child both ways in two lines; the old margin tricks are no longer needed.

Flexbox and grid on the same page

They are not competing. Grid sets out the regions of a page and the cards in a dashboard; flexbox arranges what is inside each card, a label on the left and a value on the right, an icon beside a heading, buttons in a row.

A typical document uses grid once or twice for the big structure and flexbox a dozen times for small rows. Reaching for the right one is mostly asking: is this one line, or a table of things?

Building a row with flexbox: 4 steps

  1. Put display: flex on the row's parent. The children line up horizontally by default.
  2. Give one child flex: 1. It takes whatever width is left after the fixed ones. That is the bar track, the search box, the title that should push the buttons to the right.
  3. Centre and space with align-items and gap. align-items: center for vertical centring; gap for the space between children, with nothing doubling at the ends.
  4. Let it survive a narrow screen. min-width: 0 on the flexible child so long text can shrink, and flex-wrap: wrap if the row is allowed to become two lines on a phone.

Questions people ask

What is flexbox for?

Distributing items along one direction — a toolbar, a button row, a card's internal stack. For two-dimensional layouts, grid is the better tool.

How do I push one item to the right?

margin-left: auto on that item. The automatic margin absorbs all remaining space, which is cleaner than changing the container's justification.

Why is my text overflowing its flex item?

Flex items will not shrink below their content size by default. min-width: 0 on the item allows it, and is needed for text truncation to work.

What does flex: 1 mean?

Shorthand for grow 1, shrink 1, basis 0 — the item takes an equal share of the space regardless of its content.

Keep reading

CSS min-width: 0 and why flex and grid items overflowWhy a flex or grid item refuses to shrink and pushes things off screen, and how min-width: 0CSS flex-shrink: 0 and why flex items squashWhy icons, avatars and buttons get squashed in a flex row, how flex-shrink: 0 stops it, and CSS flex-direction: row, column and the two reversesflex-direction sets which way flex items flow, and justify-content and align-items turn withReorder flex and grid items with the CSS order propertyHow the CSS order property reorders flex and grid items: default 0, negative values, ties, mCSS gap: space between items without marginsHow the CSS gap property spaces items in flexbox, grid and multi-column layouts, why it beatCSS flex-wrap: let a row of items break onto new linesflex-wrap lets flex items move onto a new line instead of shrinking or overflowing. Try it lCSS flex-grow, flex-shrink and flex-basis, worked outHow flex-grow shares free space, how flex-shrink removes overflow, and what flex: 1, flex: aHow to center a div (and pick the right way)How to center a div horizontally and vertically: flex, grid, margin auto, text-align and absCSS float: wrap text around images, and the fixes that come with itWhat CSS float is for, with live examples: wrap text around an image, clear: both, fix a parCSS justify-content: how it places items and when it does nothingAlign flex items along the main axis or grid tracks along the inline axis. Try six common vaCSS vertical-align: what middle really does, and how to center in a boxvertical-align only works on inline boxes and table cells, not on a div. Live examples of evCSS display: what each value changes, and which one to pickWhat each CSS display value changes: new lines, width and height, margins. Why width does noBuild a carousel in HTML, CSS and JavaScriptBuild an image or card carousel in plain HTML, CSS and JavaScript. Scroll-snap for swipe, a CSS grid: the one line that handles mobile for youCSS grid lays children out in rows and columns you declare. One line, repeat(auto-fit, minmaCSS media queries, and how to need fewer of themA CSS media query applies rules only when a condition holds: screen width, print, dark mode box-sizing: border-box, the first line of any stylesheetbox-sizing: border-box makes padding and border fit inside the width you wrote instead of adHow to make HTML mobile friendly: the five causesTo make HTML mobile friendly: the viewport line, fixed widths, hard-coded columns, box-sizinHTML mailto with multiple recipientsHow to write an HTML mailto link with multiple recipients, add cc and bcc, prefill a subjectHTML meta tag last modifiedThe last-modified meta tag is read by nothing. What actually carries a modification date: th