Overview

Flexbox is the one-dimensional layout primitive: a single row or column whose children grow, shrink, and align along one axis. Use it for nav bars, toolbars, button rows, and side-by-side input groups. For 2D layouts where rows and columns must align, use css-grid instead. The umbrella sits at css.

Use flex for 1D, grid for 2D

A row of buttons, a media object with avatar and text, a horizontal nav: flex. A page shell with sidebar, header, and footer: grid. The signal is whether items on different rows need to align by column. If they do, you want grid.

.toolbar {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

If you reach for flex-wrap plus manual width math to fake a 2D grid, stop. That is a grid-template-columns: repeat(auto-fill, minmax(...)) in disguise.

Name the axes: main and cross

Every flex container has a main axis (set by flex-direction) and a cross axis perpendicular to it. The property names follow:

  • justify-content aligns on the main axis.
  • align-items aligns each item on the cross axis.
  • align-content aligns wrapped lines on the cross axis (only with flex-wrap).

flex-direction: row puts the main axis horizontal; column puts it vertical, and the property meanings swap perpendicularly. If your align-items: center stops working when you flip direction, the axis flipped under you.

Use gap instead of margins

Flex supports gap in every evergreen browser since 2021. Use it.

/* Wrong: margins that leak past the last child. */
.toolbar > * + * {
  margin-inline-start: 0.5rem;
}
 
/* Right: gap, no edge cases. */
.toolbar {
  display: flex;
  gap: 0.5rem;
}

gap does not apply outside the container, does not need :last-child overrides, and survives wrapping. Tailwind utilities (gap-2, gap-x-4) compile to the same property; see tailwind.

Read flex as grow shrink basis

The shorthand flex: 1 1 0 is three values: how the item grows, how it shrinks, and its starting size before distribution.

.sidebar {
  flex: 0 0 240px;
} /* fixed width, no grow, no shrink */
.main {
  flex: 1 1 0;
} /* fill remaining space */
.button {
  flex: 0 0 auto;
} /* size to content */

Common shorthands:

  • flex: 1 means 1 1 0%. Fills remaining space, ignores intrinsic size.
  • flex: auto means 1 1 auto. Fills but respects intrinsic size first.
  • flex: none means 0 0 auto. Locked to content.

If two siblings both have flex: 1 and one keeps overflowing, the 0 basis is the reason; switch one to flex: auto.

Reach for align-content only when wrapping

align-items runs on every flex container. align-content runs only when items wrap onto multiple lines. A common bug:

/* Does nothing without flex-wrap. */
.row {
  display: flex;
  align-content: center;
}
 
/* Works: wraps then aligns the lines. */
.row {
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  gap: 1rem;
}

If align-content looks broken, check that flex-wrap is on.

Set min-width: 0 on flex children that should shrink

Every flex item defaults to min-width: auto, which means “do not shrink below intrinsic content size.” A long word or a wide table inside a flex: 1 child overflows the container instead of compressing. Fix it explicitly:

.main {
  flex: 1 1 0;
  min-width: 0;
}
.main pre {
  overflow-x: auto;
}

Same trick for min-height: 0 when items overflow vertically. Pair with overflow to recover scrolling instead of layout breakage.

Common pitfalls

  • Centering a single item: place-items: center. On a flex container, place-items shorthands align-items (works) and justify-items (ignored). Use justify-content: center; align-items: center; or switch to grid.
  • flex-direction: column and percentage heights. Percentage heights need a defined parent height; flex columns often inherit auto and silently collapse. Define height or min-height on the container.
  • Overflow that scrolls the wrong axis. A flex column with overflowing children needs overflow: hidden on the row and the column, plus min-height: 0. See the rule above.
  • Wrap on a fixed-width container. Items wrap based on basis plus content, not container width. Set basis explicitly with flex-basis or flex: 0 0 <size>.
  • Order property breaks tab order. order: -1 reorders visually only; keyboard users still tab in DOM order. See accessibility.