Tools · CSS · Flexbox playground · Guides · Why Flex Items Never End Up the Width You Gave Them

Why Flex Items Never End Up the Width You Gave Them

4 min read

You give a flex item width: 200px, and it renders at 173px. Or you set three items to flex-grow: 1 expecting three equal columns, and the one with the longest label comes out wider. Neither is a browser bug. Flexbox treats every size you give it as a starting point on one line, then runs a second step that shares out the space that is left over, or takes back the space that is missing. Most flexbox confusion is that second step happening without you noticing.

Flex items start at their basis, then share the free space along the main axis A container 600 pixels wide. Three items sit at the start at 100 pixels each, leaving 300 pixels of free space drawn as a dashed area. Below, the same items after growing with grow values 1, 1 and 2: they become 175, 175 and 250 pixels and fill the line. main axis (flex-direction: row) 100 100 100 300 free grow 1 : 1 : 2 175 175 250 the bases stay, only the free space is split by the grow ratio
Free space is what grow divides. The 100px each item started with is not part of the split.

One axis, and a size that is only a starting point

A flex container lays its children out along a single line called the main axis. With flex-direction: row that line runs in the writing direction; with column it runs top to bottom. Each item gets a starting size on that axis from flex-basis. When the basis is auto, the browser falls back to the item's width (or height in a column), and if that is also unset, to the size of its content.

Then the browser adds the bases up, adds the gaps, and compares the total with the container. The difference is the free space. If it is positive, items with a flex-grow above zero take a share of it in proportion to their grow values. If it is negative, items with a flex-shrink above zero give some back. The defaults are grow 0 and shrink 1, which is why an untouched row sits at the start and leaves a gap at the end, but squeezes when the container gets narrow.

Why "grow 1 on everything" is not equal columns

Take a 600px container with no gap and three items whose content makes them 100px, 100px and 200px wide. Give all three flex-grow: 1. The free space is 600 minus 400, so 200px, split three ways: about 67px each. The result is roughly 167, 167 and 267. Equal shares of the leftover, unequal items.

The fix is to make the starting sizes equal before the split. flex: 1 is shorthand for flex-grow: 1; flex-shrink: 1; flex-basis: 0%. With a basis of zero, all 600px is free space, and three equal grow values give three 200px items no matter what is inside them. The difference between flex-grow: 1 and flex: 1 is only the basis, and the basis is the whole difference.

Why an item refuses to shrink

Shrinking has two quirks. First, it is weighted by the basis, not just the shrink value: a 300px item with shrink 1 gives back three times as much as a 100px item with shrink 1. That keeps small items from collapsing to nothing first.

Second, flex items have min-width: auto by default, which in flexbox means "no narrower than my content". A long URL, a wide table or a pre block sets that floor, and the item stops shrinking there, pushing the row wider than its container. The usual fix is min-width: 0 on the item that holds the long content, so shrinking can actually happen and the content inside can scroll or wrap instead.

Flexbox only thinks about one line at a time. When a row wraps, each line shares its own free space, and nothing makes item 2 on line one line up with item 2 on line two. If you need rows and columns to align with each other, that is a two-dimensional layout, and the grid playground is the better tool for it.

The quickest way to stop guessing is to watch the split happen. Flexbox playground draws a real flex container: change one item's grow, shrink or basis and the other items move to make room, with the matching CSS written underneath. This guide uses it for the most common job, one fixed item and one that fills the rest, and this one follows a real header row through what happens when its words get longer.

Try Flexbox playground for free Flexbox playground