flex-basis vs width: Which Size a Flex Item Actually Starts From
A sidebar is given width: 300px and renders at 240. A set of cards with flex: 1 come out equal while the same cards with flex: auto come out ragged. A flex-basis that worked in a row stops working when the container becomes a column. All three are the same confusion: a flex item has several candidate sizes, and the algorithm picks between them in a fixed order that the property names do not advertise. This page lays out that order, shows exactly when width is ignored, and gives rules of thumb for which property to write. It belongs to Flexbox Layout Patterns in the Mastering Container Queries & Responsive Layouts guide.
Why the distinction matters
Flexbox is a negotiation. Each item states a preferred size — its flex base size — then the container compares the sum of those preferences with the space it actually has, and either hands out the surplus through flex-grow or takes back the deficit through flex-shrink. Everything interesting happens relative to the base size, so getting the base wrong makes every other flex property behave strangely.
width feels like the natural way to state a preference because it is what you would write outside flexbox. Inside a row flex container it is only a fallback: it is read when, and only when, flex-basis is auto. Writing width is therefore not wrong, but writing both width and a non-auto flex-basis produces a declaration that is silently dead, and the dead one is usually the one the next developer edits.
There is also an accessibility angle. Text zoom and user font-size preferences change content size, which feeds the automatic minimum, which can override your basis. Layouts that rely on a basis being honoured exactly are the ones that overflow at 200% text size, so it is worth knowing which sizes are negotiable and which are floors.
The resolution order
The algorithm resolves one number in stages. The diagram reads top to bottom: the first stage that produces a definite value wins, and the clamp at the bottom applies regardless of which stage won.
Two consequences fall straight out of that chart. First, width sits below flex-basis, so any explicit basis — including the 0% hidden inside flex: 1 — makes width irrelevant. Second, min-width and max-width sit outside the chain, so they are the only sizing properties that are never overridden. When you truly need "never narrower than 16rem", write min-width: 16rem, not flex-basis: 16rem, because the basis is a starting point that shrink is allowed to reduce.
The complete implementation
The demo sets up the same three items four times, varying only the flex shorthand and the width. Resize the frame and watch which rows keep equal columns and which ones track content.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>flex-basis vs width</title>
<style>
body { font: 14px/1.4 system-ui, sans-serif; margin: 1rem; }
.row { display: flex; gap: 0.5rem; margin-block-end: 1rem; }
.row > * { padding: 0.5rem; border: 1px solid #94a3b8; border-radius: 6px; }
/* A: flex: 1 = 1 1 0%. Every item starts at zero, so ALL space is
shared by flex-grow and the columns are equal regardless of text. */
.a > * { flex: 1; }
/* B: flex: auto = 1 1 auto. Items start at their content size and
only the leftover is shared, so longer text keeps a wider column. */
.b > * { flex: auto; }
/* C: width is honoured because flex-basis is auto (the initial value).
flex-shrink: 1 still allows it to go below 12rem when space runs out. */
.c > * { width: 12rem; }
/* D: width is ignored. flex-basis 8rem is not auto, so the width
declaration is dead code. min-width is the only hard floor. */
.d > * { flex: 0 1 8rem; width: 20rem; min-width: 6rem; }
</style>
</head>
<body>
<div class="row a"><div>A short</div><div>A much longer label here</div><div>A mid label</div></div>
<div class="row b"><div>B short</div><div>B much longer label here</div><div>B mid label</div></div>
<div class="row c"><div>C short</div><div>C much longer label here</div><div>C mid label</div></div>
<div class="row d"><div>D short</div><div>D much longer label here</div><div>D mid label</div></div>
</body>
</html>
Row A is what most people want from a "three equal columns" rule, and it only works because the basis is zero: nobody starts ahead. Row B is what they get when they write flex: auto or flex-grow: 1 alone, because the initial basis is auto and content size becomes the head start. Row C honours the width until the container is too narrow for three 12rem items, then shrinks them equally, since flex-shrink defaults to 1. Row D proves the width is dead: the items are 8rem wide, not 20rem, and they stop shrinking at the 6rem floor.
The key technique: shrink is weighted by the basis
Growth is simple — surplus is divided in proportion to flex-grow. Shrinking is not symmetrical, and this is where the choice of basis becomes visible. The deficit is divided in proportion to flex-shrink multiplied by the base size, so a larger item gives up more pixels than a smaller one with the same shrink factor.
The weighting is deliberate: it keeps items roughly proportional as a row gets tighter, so a wide item does not collapse its narrow neighbour to nothing. It also explains a common surprise. Two items with flex: 1 1 auto and very different content lose different amounts as the row narrows, because their bases differ; two items with flex: 1 1 0% never shrink at all in the usual sense, because a zero basis has nothing to give back — the space they occupy came entirely from growth, and shrinking growth is just growing less.
Rules of thumb for writing it
Prefer the flex shorthand over the longhands. It resets all three values together, which prevents a stray flex-grow: 1 inherited from a utility class combining with a basis you set elsewhere. The one trap in the shorthand is that its single-number form sets the basis to 0%, not auto, which is why flex: 1 and flex-grow: 1 behave differently even though they look like the same instruction.
Use width for flex items only when the same element also appears outside a flex context — a card that is sometimes in a flex row and sometimes in a block flow — and you want one declaration that works in both. Even then, leave flex-basis at auto so the width is actually read.
Variation: switching the axis
In a column container the main axis is vertical, and flex-basis now replaces height. This matters most for components that flip direction at a container query: a media object that is a row when wide and a column when narrow keeps its flex-basis: 12rem on the image, and after the flip that basis suddenly means "12rem tall".
.media {
container-type: inline-size;
}
.media__inner {
display: flex;
gap: 1rem;
}
/* Row layout: the image's basis is a width. */
.media__img {
flex: 0 0 12rem;
aspect-ratio: 4 / 3;
object-fit: cover;
}
/* Narrow: the axis flips to vertical, so reset the basis to auto.
Otherwise the image is forced to 12rem TALL and its aspect ratio
is computed from that height instead of the full width. */
@container (width < 28rem) {
.media__inner { flex-direction: column; }
.media__img { flex-basis: auto; width: 100%; }
}
The reset is the whole lesson: any basis written as a length is axis-relative, so a component that changes flex-direction must restate its bases in the new axis. Percentages follow the same rule — in a column container a percentage basis resolves against the container's height, which is often indefinite, in which case it behaves like content. For images inside flex items, aspect-ratio for responsive media covers how the ratio interacts with a basis on either axis.
Browser support
The flex, flex-basis, flex-grow and flex-shrink properties are supported in every browser in current use, and the 1 1 0% expansion of the single-number shorthand is consistent across engines. The content keyword for flex-basis, which forces content sizing even when a width is set, is newer and less consistently shipped, so prefer auto with no width when you want content sizing. The container query in the variation needs Chrome and Edge 105+, Firefox 110+ or Safari 16+.
FAQ
If I set both width and flex-basis, which one wins?flex-basis wins whenever it is anything other than auto. width is only consulted when flex-basis is auto, in which case it becomes the starting size. min-width and max-width still clamp the result either way.
What is the difference between flex: 1 and flex: auto?flex: 1 expands to 1 1 0%, so every item starts from zero and all space is shared in proportion to flex-grow, giving equal widths. flex: auto expands to 1 1 auto, so items start from their content or width and only the leftover space is shared, giving unequal widths.
Why is my flex item wider than its flex-basis?
Either flex-grow handed it extra free space, or its automatic minimum size is larger than the basis. A flex item cannot shrink below its min-content width unless min-width is set to 0, so long words or wide children push it past its basis.
Does flex-basis mean height in a column flex container?
Yes. flex-basis always sizes the main axis, so in flex-direction: column it replaces height, not width. This is why a basis written for a row layout behaves unexpectedly after switching the container to a column.
Related
- Flexbox Layout Patterns — the parent guide covering every flex pattern on this site.
- Breakpoint-Free Rows With flex-wrap — using the basis to decide when items wrap.
- Preventing Flex and Grid Overflow — the automatic minimum that overrides a small basis.
- min-content, max-content and fit-content — the content sizes a flex item falls back to.
- Motion That Scales With Container Size — animating items whose size the flex algorithm decides.
Related articles
More pages in the same section.