You have a row of tags. display: flex, flex-wrap: wrap, a modest gap. It works right up until a viewport width where five items become six, and that sixth item drops onto its own line, alone. The orphan.
That has been a "reach for a media query" moment for years. Chrome 150 ships a different answer: flex-wrap: balance.
The one keyword
The setup Ahmad Shadeed opens with in his walk-through is the classic wrapped flex row:
.list {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.5rem;
}
Swap wrap for balance, and the browser is now allowed to distribute items across the wrapped lines so a lone trailing item does not sit by itself:
.list {
display: flex;
flex-wrap: balance;
justify-content: center;
gap: 0.5rem;
}
Same box model. Same track. What changes is which items land on which line: the layout algorithm balances the wrap.
What you used to write
Shadeed catalogs the workarounds this replaces, and the list is telling because each one is a hack:
-
max-widthwith a conditionalclamp()on the flex items, tuned to force earlier wrapping at problem widths. -
display: contentson a wrapping group so its children participate directly in the parent's flex line. - An extra, invisible flex item slipped into the middle of the list so the arithmetic works out.
Each ships fine. Each is also a load-bearing detail that has to be re-tuned whenever the content changes. flex-wrap: balance moves that judgment out of the stylesheet and into the browser.
flex-line-count, the companion
The article also demos flex-line-count, a property that asks for a minimum number of lines even when the items would happily fit on fewer:
.list {
display: flex;
flex-wrap: balance;
flex-line-count: 2;
gap: 0.5rem;
}
Two lines, always, regardless of how much room the container has. That pairing is the interesting one. balance decides how many items sit on each line; flex-line-count decides how many lines exist in the first place. Together they get closer to the masonry-ish pattern people have been faking with grid for years, only with flex holding the reins.
Where support stands
flex-wrap: balance is in Chrome 150, Chrome only at the time Shadeed wrote the piece. No cross-browser Baseline. In production this is a progressive enhancement: browsers that do not recognize the value fall back to whatever flex-wrap computed to before, so you get today's slightly-off layout instead of a broken one.
Feature-detect it when the balanced result carries more weight than a polish pass:
@supports (flex-wrap: balance) {
.list { flex-wrap: balance; }
}
What to try on your next layout
Pick your worst offender. A primary nav. A tag cloud. A row of social icons. Anywhere the wrap point produces a stray element at some viewport width, drop flex-wrap: balance on the parent and see what the browser does with it. If the layout also wants a fixed row rhythm, layer flex-line-count and watch the two properties negotiate.
Grid has had the masonry conversation for a while, and subgrid has absorbed a lot of what wrap-heavy flex used to be forced into. flex-wrap: balance is a quieter move. Flex is not competing with grid here. It is finally holding its own contract without asking authors to backstop it with clamp().
Top comments (0)