skip to content

Three items in a flex row all have flex-grow: 1 but different amounts of text, and they end up unequal widths. How does flex-grow actually distribute space, and what would make them equal?

level: middleimportance: must knowfreq 68%

answer

  1. Grow divides the remainder, not the whole
  2. Base sizes survive into the final layout
  3. Zero the basis to equalise
  4. Factors are ratios of the free space
  5. Sub-one factor sums leave space unused

basics

~20 s

flex-grow shares only the leftover free space, not the whole container. With flex-basis: auto each item starts at its content width and then adds an equal slice of the remainder, so they stay unequal. Use flex: 1, which sets flex-basis to 0, for equal widths.

solid answer

~50 s

`flex-grow` never divides the container — it divides the **free space** that is left after every item's base size is accounted for. With `flex-grow: 1` and the default `flex-basis: auto`, each item starts at its content width, the leftover is split into equal slices, and each item gets its content width *plus* one slice, so a wordier item stays wider. The fix is `flex: 1`, which expands to `1 1 0%`: with every base size at zero, the entire container becomes free space and equal grow factors produce equal widths. The factors are proportions, so `flex: 1` and `flex: 2` in a 600px row give 200px and 400px. One extra rule worth knowing: if the grow factors across the line sum to less than 1, only that fraction of the free space is distributed and the rest stays empty.

code

css · 7 lines
css
.row { display: flex; width: 900px; }

/* content widths 100px / 200px / 300px, free space 300px */
.row.unequal > * { flex-grow: 1; }  /* -> 200px / 300px / 400px */

/* every base size is 0, so free space is the full 900px */
.row.equal > * { flex: 1; }         /* -> 300px / 300px / 300px */

go deeper

for a junior

Know the practical rule: use flex: 1 when you want equal columns, and expect flex-grow: 1 on its own to leave wordier items wider. Be able to point at flex-basis as the reason.

for a middle

Do the arithmetic out loud — subtract the base sizes from the container to get free space, then split it by the factors. Explain the ratio behaviour of flex: 1 versus flex: 2.

for a senior

Diagnose the near misses: padding under content-box, a max-width capping one item and redistributing its space, or a non-flexible sibling changing the free-space budget. Say when you would move the layout to grid instead.

for a principal

Own the choice of sizing model across a component library — flex distribution is per line and content-aware, grid tracks are shared across rows — and set the box-sizing and spacing conventions that stop equal-column bugs recurring.

## The algorithm in four steps For each flex line, the browser: 1. Computes each item's **flex base size** from `flex-basis` (with `auto` deferring to `width`/`height`, then to content). 2. Clamps each base by the item's own min and max constraints to get its **hypothetical main size**. 3. Computes **free space** = the container's inner main size − the sum of those hypothetical sizes (plus any `gap`). 4. If free space is positive, distributes it in proportion to `flex-grow`; if negative, distributes the deficit in proportion to `flex-shrink` scaled by base size. Step 3 is the one that answers the question. `flex-grow` operates on the *remainder*, never on the whole container, so whatever differences existed in the base sizes survive into the final layout. ## The worked example A 900px row with three items whose content widths are 100px, 200px and 300px, all `flex-grow: 1`, `flex-basis: auto`: - Sum of base sizes = 600px. - Free space = 900 − 600 = 300px. - Three equal grow factors → each gets 100px. - Final: **200px, 300px, 400px** — still unequal, just less unequal than before. Now change one declaration to `flex: 1`, i.e. `1 1 0%`: - Sum of base sizes = 0. - Free space = 900px. - Each item gets 300px. - Final: **300px, 300px, 300px** — genuinely equal. ```css .unequal > * { flex-grow: 1; } /* content size + equal share of leftover */ .equal > * { flex: 1; } /* base 0, so equal shares of everything */ ``` That single difference — basis `auto` versus basis `0` — is the whole answer, and it is why `flex: 1` became the equal-columns idiom. ## Factors are ratios, not units Grow factors are weights, compared against the sum of all factors on the line. With `flex: 1` and `flex: 2` in a 600px row, the total is 3, so the items take 1/3 and 2/3 → 200px and 400px. With bases that are *not* zero, the same ratio applies to the leftover only: two items with 100px bases in a 400px row have 200px free, so factors 1 and 3 add 50px and 150px, giving 150px and 250px — not a 1:3 ratio overall. This is also where `fr` in CSS Grid differs: an `fr` track distributes space with a min-content floor built into `minmax(auto, 1fr)`, while a flex item's floor comes from its own min constraints. Reasoning about them as "the same thing" produces wrong predictions. ## The sub-one rule The specification has a rule most people never meet: if the sum of the flex factors on a line is **less than 1**, only that fraction of the free space is distributed. A single item with `flex-grow: 0.5` and 400px of free space grows by 200px and leaves 200px empty. Once the factors sum to 1 or more, all free space is used. Fractional factors below 1 are legal and occasionally useful for "grow, but only a bit". ## Why equal factors can still give unequal boxes Even with `flex: 1` on everything, items sometimes come out different widths. The usual causes: - **Padding and border under `content-box`.** `flex-basis: 0` is a *content* base of zero, so each item's padding and border are added on top. Two items with 20px and 40px of horizontal padding will differ by 40px. `box-sizing: border-box` removes this. - **A min or max constraint.** `max-width` caps an item's growth, and the space it declined is redistributed to the others; a `min-width` floors one and takes space away. - **An item that is not actually flexible.** `flex: none` or `flex-shrink: 0` on one child changes the free space everyone else divides. ## Answering it out loud The crisp version is: "`flex-grow` splits leftover space, not the container. With `flex-basis: auto` the items start at their content sizes, so equal grow factors keep them unequal. `flex: 1` sets the basis to `0`, which makes the whole container leftover space and the items equal — assuming matching padding under `border-box`." If the interviewer pushes, do the arithmetic on a concrete container width; showing the free-space subtraction is what demonstrates you know the algorithm rather than the idiom.

  • Two items have flex: 1 and identical content, yet one renders wider. What would you check first?
    Padding and border under `box-sizing: content-box`: `flex-basis: 0` zeroes the *content* box only, so extra padding is added on top of the equal share. After that, check for a `min-width` or `max-width` clamping one item, and for a sibling that is not flexible (`flex: none`) changing how much free space the others divide.
  • What happens if the flex-grow factors on a line add up to less than 1?
    Only that fraction of the free space is distributed. One item with `flex-grow: 0.25` and 400px of free space grows by 100px and the remaining 300px is left unfilled. It is a deliberate spec rule that lets you say "absorb part of the slack"; once the factors reach 1 in total, all free space is consumed.
  • Is flex: 1 on a flex item equivalent to a 1fr grid track?
    They are close but not identical. Both distribute leftover space proportionally, but a `1fr` track is `minmax(auto, 1fr)`, so it has a min-content floor built in, and grid sizes tracks across the whole container including items in other rows. A flex item's floor comes from its own min constraints, and sizing is per flex line.

Think of a bonus pool: flex-basis is each person's existing salary and flex-grow is their share of the bonus. Equal bonuses do not make unequal salaries equal — you have to zero the salaries first.

saying these in an interview costs you the question

  • Says flex-grow divides the whole container width
  • Thinks equal flex-grow always yields equal widths
  • Believes flex-grow: 2 makes an item twice as wide overall
  • Treats flex-grow as a percentage of the container
  • Ignores padding when explaining unequal flex: 1 items

context