---
title: "CSS: Flexbox"
slug: "css-flexbox"
category: "frontend"
tags: ["frontend", "css", "flexbox", "layout"]
status: "stable"
last_updated: 2026-05-14
summary: "Flex for 1D layouts: main vs cross axis, grow/shrink/basis, gap over margins, and the overflow bugs that bite every new flex user."
related:
  [
    "[[frontend/css]]",
    "[[frontend/css-grid]]",
    "[[frontend/css-custom-properties]]",
    "[[frontend/tailwind]]",
    "[[frontend/accessibility]]",
  ]
---

## 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 [[frontend/css-grid]] instead. The umbrella sits at [[frontend/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.

```css
.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.

```css
/* 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 [[frontend/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.

```css
.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:

```css
/* 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:

```css
.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 [[frontend/accessibility]].

## Related

- [[frontend/css]]
- [[frontend/css-grid]]
- [[frontend/css-custom-properties]]
- [[frontend/tailwind]]
- [[frontend/accessibility]]
- [[seo/page-speed]]
