I Can Finally Delete My max-height: 9999px Animation Hack
CSS transitions have never been able to animate to height: auto, because auto isn't a number the engine can interpolate. calc-size() and interpolate-size finally give it real numbers — no JavaScript, no magic-number ceiling.

Open any accordion, dropdown, or "show more" panel you've shipped and grep its CSS for max-height. You'll find a number: 500px, 800px, 9999px. Ask whoever wrote it why that number, specifically, and watch them shrug. "Felt safe."
It isn't safe. It's a guess wearing a unit. And for over a decade that guess was the best CSS could do, because there's a rule you've never been able to break: you cannot transition to height: auto. Not "it's awkward" — it genuinely does not work. That finally changed. Almost nobody's using it yet.
Here's the fix you've probably shipped, because it's the first thing anyone tries:
It works in the demo. It works in the PR review. Then three months later a support rep pastes a 40-line answer into the FAQ panel this was built for, the real content hits 640px, and the panel clips the last two lines with no scrollbar and no error — it just silently loses content. You bump the number to 9999px to "fix" it for good, and now every short panel — the ones that are actually 80px tall — takes the same visible beat to finish opening, because the browser is animating from 0 to 9999 and just happens to arrive at the real content early. You can see the pause if you watch closely. Users don't watch closely; they just feel that something's slightly off.
So you reach for the other fix, the one that actually measures reality:
This one's honest — it reads the real height instead of guessing. But now every toggle forces a layout read before the animation can even start, and if the content inside can change while the panel is open (an image loads, a comment thread grows), your cached scrollHeight goes stale and you need a ResizeObserver just to keep the number honest. You've traded a wrong number for a right number that needs its own maintenance.
Quick check before you scroll: is there a max-height: with a suspicious round number in something you shipped this year? There usually is.
Here's the part that's easy to miss: this isn't a case where you were holding CSS wrong. A CSS transition works by taking a start value and an end value and asking the engine to compute the in-between frames — 0px, 40px, 120px, 480px, and so on until it lands on the target. That only works if both ends are actual numbers.
auto was never a number. It's an instruction: "run layout, and whatever height that produces, use it." The browser can't interpolate toward an instruction — it doesn't know the destination until layout has already run, and running layout is the thing the animation is supposed to be showing you getting closer to. So historically, the engine's only options were to snap directly to the computed height (no animation) or refuse to run the transition on that property at all. Every hack above exists to hand the engine a real number instead, because the engine genuinely couldn't make one up.
Chromium 129 shipped the piece that was missing: a way to tell the engine "you're allowed to treat intrinsic keywords — auto, max-content, fit-content — as numbers you can animate toward," instead of refusing on principle.
That's it. No scrollHeight, no guessed ceiling, no ResizeObserver. interpolate-size defaults to numeric-only — the old, safe behavior — so setting it to allow-keywords once on :root is what flips the switch for the whole page. The browser now resolves auto's real computed height before the transition starts, then genuinely animates toward it, the same way it would animate toward 320px.
Runs right in your browser — poke at it and watch the concept react live.
Need something more surgical than a flat toggle — a percentage of an intrinsic size, say, or a multiple of min-content for a custom easing step? That's what calc-size() is for: it lets you do math on an intrinsic keyword the way calc() does math on a length.
size inside the function stands in for whatever the basis keyword (auto, min-content, max-content, fit-content, stretch, or contain) resolves to. Using calc-size() anywhere in a value automatically turns on interpolate-size: allow-keywords for that value, so most of the time the plain height: auto version above is all you need — reach for calc-size() only when you actually need to compute something on top of the keyword.
The spec authors also wired this into <details> directly, which is worth stealing verbatim:
A native disclosure widget, animating open and closed, with zero JavaScript and zero measured pixels.
interpolate-size and calc-size() currently ship in Chrome and Edge 129+ (and their Chromium-based siblings). As of this writing, Firefox and Safari don't support either one — there are open requests to add them, but no shipped implementation yet.
The good news is how it fails. interpolate-size: allow-keywords is a genuinely safe rollout: a browser that doesn't understand it just keeps the default numeric-only behavior, which means the height: auto transition doesn't error or break — it just doesn't animate. The panel snaps open instantly, exactly like it would have before this property existed. Nothing clips, nothing crashes, and you don't need a JavaScript feature-detect to stay safe; wrap it in @supports (interpolate-size: allow-keywords) { … } only if you want to swap in a fallback transition for unsupported browsers, not because the unguarded version is dangerous.
That makes it a real progressive enhancement, not a bet: ship it today, and roughly a third of your users get a smooth open/close for free while the rest get the exact snap behavior they already have.
The max-height: 9999px in your codebase isn't a bug you introduced — it's a scar from a real gap in CSS that's only now closing. You don't need to rip it out today; Firefox and Safari users still need it. But the next accordion, the next FAQ panel, the next "show more" you build gets one property on :root instead of a guessed ceiling or a ResizeObserver.
Go find your own max-height: guess and try swapping it for interpolate-size: allow-keywords. What number were you hiding behind — and did you ever find out the hard way that it was too small?
Think it clicked? Take the 8-question quiz →
Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.
Thanks for reading! Let's stay connected:
- ⭐ GitHub — follow me and star the projects: github.com/parsajiravand
- 💬 Discord — join the frontend best-practices community: discord.gg/d9KRhuAwQ
- 📸 Instagram — frontend best practices, daily: @bestpractice___
- 💼 LinkedIn — linkedin.com/in/parsa-jiravand
- ✉️ Email (work & contract inquiries): bestpractice2026@gmail.com
Keep reading
One post a day, in your inbox
Each one with a runnable playground and a quiz. No pitch, no digest, unsubscribe in one click.
Originally published on dev.to