Skip to content
GRUDGED Free audit
§ Field notes for web developers ·

Your CSS Grid Row Won't Scroll? The min-height: 0 Trap

A grid or flex child that should scroll instead shoves the whole layout taller. The one-line reason — min-height defaults to auto, not zero — and the fix.

Here’s a layout bug I’ve hit in every framework I’ve ever used, and it always looks like the browser ignoring me. You build a column: a fixed header on top, then a content area underneath that’s supposed to scroll. You give the content area flex: 1 (or 1fr in a grid), set overflow: auto, drop in a long list — and instead of scrolling, the list pushes the entire layout taller. Your header scrolls off the top of the window. overflow: auto does nothing.

You check the overflow property three times. It’s right. The browser isn’t broken, and neither are you. You’ve hit one of the most quietly confusing defaults in CSS.

The setup that breaks

.app {
  display: grid;
  grid-template-rows: auto 1fr;   /* header, then fill */
  height: 100vh;
}
.content {
  overflow: auto;                 /* should scroll... doesn't */
}

The flex version of the same bug:

.col  { display: flex; flex-direction: column; height: 100vh; }
.list { flex: 1; overflow: auto; }   /* should scroll... doesn't */

In both cases the scrolling region grows to fit its content and shoves everything else around, as if overflow weren’t set at all.

Why it happens

A flex or grid item’s min-height defaults to auto, not 0 (same for min-width). And auto, in this context, means “at least as tall as my content.”

So your 1fr / flex: 1 track has two instructions that conflict: “share the leftover space” and “never be shorter than your content.” The minimum-size rule wins. The track refuses to shrink below the intrinsic height of everything inside it, so it grows the container instead — and because the box expanded to fit all the content, there’s no overflow left for overflow: auto to scroll. The constraint quietly beats your sizing.

The fix

Set min-height: 0 on the item that should scroll:

.content { overflow: auto; min-height: 0; }

The catch that trips people the second time: it has to be on the whole chain. Every flex or grid ancestor between the fixed-height root and the scrolling element needs min-height: 0 too. Miss one — a wrapper <div> in the middle that’s also a flex container — and the auto minimum reappears there and re-inflates the layout. When a scroll region still won’t behave after you’ve fixed the obvious element, walk up the tree and add it to every flex/grid parent.

The horizontal twin: min-width: 0

The exact same default causes the other classic: a flex item that won’t shrink or truncate. You put text-overflow: ellipsis on a label inside a flex row, the text is long, and instead of an ellipsis it blows the row wider than the container. Cause: min-width: auto won’t let the item shrink below its content’s width. Fix: min-width: 0 on the flex item. Same bug wearing a different hat.

Spotting it in two seconds

Three symptoms, one root cause:

  • Something that should scroll grows the page instead.
  • overflow: auto/hidden “does nothing.”
  • A flex item with text-overflow: ellipsis refuses to truncate.

All three are min-height / min-width: auto doing exactly what the spec says, which is rarely what you want inside an app layout.

Rule of thumb

When you build a fixed-height shell with scrolling regions inside it, add min-height: 0 (and min-width: 0 anywhere you truncate) to every flex and grid container in the chain, by default. It isn’t a hack — it’s deliberately opting out of a default that exists for good reasons, just not the ones that apply when you’re laying out an application.

Further reading


I’m Chris Moore — an independent developer and consultant in Henderson, NV, working under Grudged LLC. I build and rescue the operational systems small teams run on. If a layout bug like this has eaten your afternoon, get in touch.

← All field notes Talk to Chris Moore →