
In this article, I break down how the new interpolate-size and transition-behavior properties finally solve the "height: auto" problem in CSS. We walk through how to ditch old hacks for native, smooth transitions that handle both dynamic math and discrete display states the right way.
In this article, I want to show you how to finally solve one of the most annoying hurdles in CSS development: animating elements with dynamic heights.
If you’ve been building for the web for a while, you’ve likely felt the frustration of trying to animate an accordion or a dropdown. For years, we’ve had to rely on "hacks" like animating max-height to a massive, arbitrary number or bringing in a JavaScript library just to measure pixels. It works, but it’s never felt like "the right way" to me.
Today, we have two new properties interpolate-size and transition-behavior that handle the math and the logic natively. Let's walk through how to implement them.
What is the "Auto" Problem?
The issue was never the animation itself, but the math. Browsers are great at calculating the distance between 0px and 500px, but they traditionally couldn't calculate the midpoint between 0px and a keyword like auto.
When you toggled a class, the browser would simply "snap" to the final height because it didn't have a numeric path to follow.
To fix the math, we use interpolate-size. I like to think of this as giving the browser permission to calculate the "uncalculatable."
The best way to implement this is to set it at the :root level. Since it's an inherited property, you enable it once and it works for every component on your site.
:root {
/* This tells the engine to allow animations for keywords like auto or fit-content */
interpolate-size: allow-keywords;
}
.accordion-content {
height: 0;
overflow: hidden;
transition: height 0.4s ease-in-out;
}
.accordion-content.is-open {
/* Thanks to the root property, this now slides smoothly */
height: auto;
}
Even with the height solved, we still have to deal with the display property. For a clean DOM and better accessibility, we usually want to use display: none when an element is hidden.
The problem? display is a discrete property—it’s either there or it isn't. Usually, if you toggle it, the element vanishes instantly, which kills your smooth height or opacity transition mid-flight.
transition-behavior: allow-discrete is the solution. It tells the browser to wait until the transition duration finishes before it actually flips the display switch.
.dropdown {
display: none;
opacity: 0;
/* 'allow-discrete' ensures the element stays 'block' until the fade ends */
transition:
display 0.3s allow-discrete,
opacity 0.3s;
}
.dropdown.is-open {
display: block;
opacity: 1;
}
When we combine these, we get a component that is performant, accessible, and smooth. Here is how I usually structure a panel that needs to both slide and fade.
I’ll explain these transition values from left to right: first we define the property (like display), then the duration (0.5s), and finally the behavior (allow-discrete).
:root {
interpolate-size: allow-keywords;
}
.panel {
display: none;
height: 0;
opacity: 0;
overflow: hidden;
/* Walkthrough: display waits for the others, height slides, opacity fades */
transition:
display 0.5s allow-discrete,
height 0.5s,
opacity 0.5s;
}
.panel.is-active {
display: block;
height: auto;
opacity: 1;
}
I'm a big advocate for progressive enhancement. We don't need to wait for 100% support to start using these tools, as long as the fallback is acceptable.
transition-behavior: This is very stable now (about 89% support). It’s ready for prime time in Chrome, Firefox, and Safari.
interpolate-size: This is the newer piece of the puzzle (around 71%). It works beautifully in Chromium browsers, and the other engines are moving quickly to catch up.
If a user is on an older browser, they won't see a broken layout; the panel will just snap open instantly. In my experience, that's a perfectly fine fallback for the sake of writing cleaner, more maintainable CSS.
If you want to be extra careful, you can wrap your root opt-in in a feature query:
@supports (interpolate-size: allow-keywords) {
:root {
interpolate-size: allow-keywords;
}
}
This approach allows us to ditch the old 1000px max-height hacks and write code that finally does exactly what we intend. Give it a try on your next project—it’s a much more satisfying way to build.
gemmaI ported the whole Gemma-4 family — E2B, E4B, 12B, 31B, and the 26B-A4B MoE — to run on...
communityHey DEV, I'm Tobore. Let's actually connect. I've been on here for a while now, mostly writing and...
ai(yep, kinda clickbait, just for the funsies 😊) At the beginning of the year, I relaunched my...
aiMy laptop was sitting idle with the fan at full tilt. Nothing was running that I knew of. The culprit...
githubactionsI Built a Thing! TL;DR — Google Gemini-based Pull Request reviews and Issue Triaging for...
aiI've been hearing the word "harness" thrown around a lot lately. I assumed it just meant "the IDE" or...
Workflows from the Neura Market marketplace related to this DeepSeek resource