skip to content

A 240px-wide logo in a flex toolbar gets squeezed on narrow screens even though its width is set, and the widest item loses the most space. Explain what the shrink algorithm is doing and how you would fix the logo.

level: seniorimportance: should knowfreq 48%

answer

  1. Width is a starting point, not a floor
  2. Shrink is on by default; grow is not
  3. Deficit shared in proportion, not equally
  4. Weighted by shrink factor times base size
  5. Opt out with flex: 0 0 length

basics

~20 s

Flex items shrink by default because flex-shrink is 1, and the deficit is split in proportion to flex-shrink multiplied by each item's base size, so wider items give up more. Pin the logo with flex-shrink: 0, or flex: 0 0 240px.

solid answer

~50 s

Two things are happening. First, `flex-shrink` defaults to `1`, so a declared `width` is a starting point, not a floor — when the line overflows, every item is fair game. Second, shrinking is weighted: the browser distributes the deficit in proportion to each item's `flex-shrink` **multiplied by its flex base size**, so a 300px item loses more than a 200px item at the same shrink factor. That weighting is deliberate — equal absolute shrinkage would crush small items out of existence first. The fix for the logo is to opt it out with `flex-shrink: 0`, and I'd usually write the whole contract as `flex: 0 0 240px` so the base size and the inflexibility live in one declaration. Shrinking is also floored by each item's automatic minimum size, so an item may stop shrinking before the math says it should.

code

css · 7 lines
css
.toolbar { display: flex; align-items: center; }

/* pinned: starts at 240px, never grows, never shrinks */
.toolbar .logo { flex: 0 0 240px; }

/* absorbs whatever is left over, and gives way first when space runs out */
.toolbar .nav { flex: 1; }

go deeper

for a junior

Know that flex items shrink by default and that a set width will not hold on its own. Be able to name flex-shrink: 0 as the way to stop it.

for a middle

Explain the weighting — deficit shared in proportion to flex-shrink times flex base size — and work a two-item example through to final pixel sizes.

for a senior

Diagnose the layout from symptoms, name the tradeoff you accept by pinning an item (overflow instead of compression), and mention that shrinking is floored by each item's minimum size so a line can still overflow.

for a principal

Set the convention: which elements in a shared shell are allowed to be inflexible, what the small set of sanctioned shrink factors means, and where the responsive strategy should switch to wrapping or a breakpoint instead of squeezing further.

## Shrinking is the default, growing is not A flex item you never configured behaves as `flex: initial`, i.e. `flex-grow: 0; flex-shrink: 1; flex-basis: auto`. The asymmetry catches people out: items will *not* expand into free space unless you ask, but they *will* be compressed below their declared size without being asked. Flexbox's priority is fitting the line, and `width` is an input to that negotiation rather than a guarantee. ## The weighted-shrink formula When the sum of the items' hypothetical main sizes exceeds the container's inner main size, the difference is the **negative free space**, and it is distributed using a *scaled* shrink factor: ``` scaled factor(item) = flex-shrink(item) × flex base size(item) shrinkage(item) = deficit × scaled factor(item) / Σ scaled factors ``` Worked example: a 400px row with two items whose bases are 300px and 200px, both `flex-shrink: 1`. - Deficit = (300 + 200) − 400 = 100px. - Scaled factors: 300 and 200; sum 500. - Item A loses 100 × 300/500 = 60px → **240px**. - Item B loses 100 × 200/500 = 40px → **160px**. So the wider item absorbed 60% of the cut. This is why your logo shrinks *more* than a narrow icon next to it: it is bigger, so it is charged more. ## Why weight by base size at all If the deficit were split evenly in pixels, a 40px icon beside a 600px content column would be asked to give up the same 50px, and the icon would collapse to nothing while the column barely noticed. Weighting by base size makes shrinkage *proportional* — every item loses roughly the same percentage of itself — which keeps small items visible. Grow is not weighted this way, and that asymmetry is intentional: growth by base size would make already-large items run away. ## Fixing the toolbar Opt the fixed element out of the negotiation: ```css .toolbar { display: flex; } .toolbar .logo { flex: 0 0 240px; } /* base 240px, no grow, no shrink */ .toolbar .nav { flex: 1; } /* absorbs the remaining space */ ``` `flex: 0 0 240px` states the whole contract in one line: start at 240px, take none of the surplus, absorb none of the deficit. `flex-shrink: 0` alone works too if you want to keep `width: 240px` as the source of the size (`flex-basis: auto` will defer to it). What does *not* work is escalating the `width` declaration — `!important` on a `width` changes the base size, not the item's shrinkability. Be aware of the tradeoff you have just made: an item with `flex-shrink: 0` will overflow the container rather than compress when the viewport gets small enough. That is usually correct for a logo with a fixed asset, but for text-bearing elements it converts a squeeze into an overflow, so pair it with a wrap or a media query at the breakpoint where the line genuinely runs out of room. ## Shrinking has a floor The formula is not the last word. Each item's shrunk size is clamped by its minimum size, and flex items have an **automatic minimum size** rather than zero — so an item can stop shrinking while the arithmetic still wants it smaller. When that happens the item is frozen at its floor and the remaining deficit is redistributed across the items that can still shrink, which is why a line sometimes overflows even though nothing has `flex-shrink: 0`. ## Choosing shrink factors deliberately Beyond `0` and `1`, explicit factors let you rank what gives way first. A `flex-shrink: 3` on a decorative panel next to `flex-shrink: 1` on the main content means the panel absorbs three times the cut per unit of base size — a reasonable way to encode "squeeze the chrome before the content". Keep the set of factors small and documented; a codebase where every component picks its own shrink number is hard to reason about, because the outcome for any one item depends on the factors of every sibling on the same line. ## The one-breath answer "Items shrink by default — `flex-shrink` is `1` — and the deficit is shared in proportion to shrink factor times base size, so the biggest item pays the most. To hold the logo at 240px, take it out of the negotiation with `flex: 0 0 240px`, and accept that it will now overflow instead of compress at very small widths."

  • What is the tradeoff of setting flex-shrink: 0 on an item?
    It converts compression into overflow. The item keeps its size, so once the line runs out of room the content spills past the container instead of squeezing. That is fine for a fixed-size logo, but for text-bearing items it trades a cosmetic squeeze for a broken layout, so it usually needs a wrap or a breakpoint to back it up.
  • Why is flex-grow not weighted by base size the way flex-shrink is?
    Because the goals differ. Weighting shrinkage by size makes every item lose a similar *percentage*, which stops small items collapsing to nothing. Weighting growth the same way would compound existing differences — big items would run away with the free space — so growth is distributed by the raw factors instead, which is exactly what makes `flex: 1` with a zero basis produce equal sizes.
  • When would you use a flex-shrink value other than 0 or 1?
    To rank what gives way first on a crowded line. `flex-shrink: 3` on a secondary panel beside `flex-shrink: 1` on the main content means the panel absorbs three times the cut per unit of base size. Keep the vocabulary of factors small and documented, since an item's outcome depends on every sibling's factor on the same line.

saying these in an interview costs you the question

  • Says a declared width cannot be overridden by flexing
  • Thinks the deficit is split equally in pixels
  • Believes flex-shrink defaults to 0 like flex-grow
  • Reaches for !important on width to stop shrinking
  • Claims larger flex-shrink numbers always shrink the item more, regardless of size

context