
Stop Using `max-height` for Transitions: How `calc-size()` Finally Solves the `height: auto` Problem
Stop reaching for JavaScript or restrictive max-height hacks—the new CSS intrinsic sizing primitives are here to solve our oldest layout animation struggle.
We’ve all spent a collective decade lying to our browsers just to get a simple accordion to slide open smoothly. If you’ve ever typed max-height: 1000px and then tweaked the transition duration until the "jank" felt slightly less offensive, you know exactly what I’m talking about.
For years, animating from height: 0 to height: auto has been the "final boss" of CSS layout. Browsers simply didn't know how to interpolate between a fixed number and a keyword. But the CSS Working Group has finally heard our prayers (and our GitHub issues), and we're getting a real solution: calc-size().
The hacky past we’re leaving behind
Before we look at the new shiny stuff, let’s acknowledge the struggle. The industry standard for "good enough" has been the max-height trick.
/* The classic hack */
.accordion-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
.accordion-item.is-open .accordion-content {
/* We pick a number that's 'big enough' but not too big */
max-height: 1000px;
}This works, but it's fundamentally broken. If your content is only 100px tall, the browser still calculates the transition for a 1000px range. This results in a weird delay when you try to close the element, as the browser spends the first 90% of the transition duration "closing" empty space.
Then came the CSS Grid trick—using grid-template-rows: 0fr to 1fr. It’s clever, and it actually works quite well, but it feels like using a sledgehammer to hang a picture frame. It’s a layout engine hack for a transition problem.
Enter calc-size()
The calc-size() function is a new CSS primitive that allows us to perform calculations on intrinsic sizes like auto, min-content, and fit-content.
Think of it as the missing link. It takes a "size source" (the keyword) and an operation. Because it explicitly tells the browser to evaluate the intrinsic size, the browser can finally figure out the math required to animate it.
Here is how you actually use it to solve the height: auto problem:
.dropdown-menu {
height: 0;
overflow: hidden;
transition: height 0.4s ease-in-out;
}
.dropdown-menu.is-visible {
/* This tells the browser: 'Treat auto as a measurable size' */
height: calc-size(auto, size);
}In this example, calc-size(auto, size) is basically saying: "Find the height of auto, and then just return that value." Because it’s wrapped in this function, the CSS transition engine can now treat that auto value as a specific pixel amount it can animate toward.
The even better way: interpolate-size
If writing calc-size() every time feels tedious, the spec authors included a "set it and forget it" property that is arguably even more powerful: interpolate-size.
By setting interpolate-size: allow-keywords on the root or a parent container, you’re telling the browser: "Hey, if I try to transition to auto, don't snap it—actually animate it."
:root {
/* Opt-in to smooth transitions for intrinsic keywords */
interpolate-size: allow-keywords;
}
.card-body {
height: 0;
overflow: hidden;
transition: height 0.3s ease;
}
/* Now this works perfectly with no hacks! */
.card:hover .card-body {
height: auto;
}I love this because it respects the way we *want* to write CSS. We want to use height: auto because it's resilient. Now we can, without sacrificing the user experience.
Why this actually matters for your performance
It’s not just about aesthetics. When we use the max-height: 1000px hack, the browser has to do a lot of work under the hood. It’s calculating layout for a potentially massive box that isn't there.
By using calc-size() or interpolate-size, the browser knows exactly what the target dimensions are before the animation starts. This leads to smoother frame rates and less "layout thrashing," especially on low-powered mobile devices where every CPU cycle counts.
Can I use it today?
Here is the "gotcha": as of right now, this is primarily landing in Chromium browsers (Chrome, Edge, Opera). It’s currently behind a flag or in the latest stable releases depending on when you read this.
However, it is a progressive enhancement.
If you use the interpolate-size property, browsers that don't support it will simply snap the height from 0 to auto immediately, which is exactly what they do now. Your site doesn't break; it just gets better for users on modern browsers.
.my-element {
height: 0;
overflow: hidden;
transition: height 0.3s ease;
/* Modern Browsers */
interpolate-size: allow-keywords;
}
.my-element.open {
height: auto; /* Animates in Chrome, snaps in others */
}Wrapping Up
The era of the "1000px hack" is finally coming to an end. It’s a small change, but it removes one of the most frustrating papercuts in web development.
I’ve started adding interpolate-size: allow-keywords to my base resets in my personal projects already. It’s one of those rare CSS features that lets you write *less* code while achieving a *better* result. Stop fighting the box model and let the browser do the math for you.


