min-height is silently breaking your flexbox layout
You’ve built the classic app shell. Top bar across the top, sidebar down the left, and a big table in the content pane. You gave the table body overflow-auto, because obviously the table should scroll, not the page.
And yet: the whole page scrolls. The top bar scrolls right off the screen, the table’s own scrollbar never shows up, even though every element in the chain has height: 100%.
The culprit is a flexbox default: min-height: auto.
By default, every flex item in a column layout has min-height: auto, which means:
“I will not become shorter than my content’s intrinsic height, no matter what the flex algorithm says.
You asked for flex-1. But flexbox quietly overrode you.
Here’s the shell:
<style> html, body { height: 100%; }</style>
<div class="flex h-full flex-col"> <header>top bar</header>
<div class="flex flex-1"> <nav>sidebar</nav> <main class="h-full overflow-auto">700px of table</main> </div></div>- The shell is
flex flex-col h-full, viewport height. - The sidebar row is
flex-1, so the flex algorithm wants to size it to exactly “viewport minus top bar”. - But its content (that 700px table) is taller than that. With the implicit
min-height: auto, the row’s minimum height is its content’s height, so the row wins the argument againstflex-1, grows to fit the table, the shell overflows the viewport, and the browser scrolls the entire oage.
And the table’s overflow-auto never fires. main’s h-full resolves against a row that already grew to fit the content, so “100%” is big enough to hold everything. Nothing overflows in the one place you wanted overflow.
<div class="flex flex-1 min-h-0"></div>min-h-0 replaces min-height: auto with 0, telling the row “you’re allowed to be smaller than your content.”
That caps the rows height at the remaining viewport height, and every height below it snaps into place. The content pane gets a real bounded height, main’s h-full finally means “pane height” instead of “content height”, and the overflow lands where it’s handled: the table’s overflow-auto scroll container.
The dashed border is the “viewport”. Same markup, same 14 rows; the only difference is min-h-0 on the middle row. On the left, the top bar scrolls away with everything else. On the right, it stays put and the table scrolls like you intended.
In a row layout the same default shows up as min-width: auto, and its favorite victim is text truncation. If you’ve ever stacked truncate on a flex child and watched it stubbornly not truncate while blowing out the layout, that’s this exact bug rotated 90 degrees. min-w-0 is the fix.
You often need a panel that grows to fill available space, but stops growing once it runs out of content, and scrolls only when it has to.
flex: 1;min-height: 0;max-height: max-content;overflow-y: auto;max-height: max-content caps the panel at “as tall as my content wants to be”, so it never greedily hoards empty space. It takes room while it needs it, stops when it doesn’t, and scrolls when it can’t get enough. It doesn’t want to scroll, but it will if it has to.
Any time an h-full / overflow-auto chain passes through a flex item, that item needs min-h-0
(or overflow-hidden)
-
Per the flexbox spec, the
autominimum only resolves to the content-based minimum whenoverflowisvisible; otherwise it’s zero. ↩