Why does a CSS transition on `height` do nothing when the target value is `height: auto`, and which techniques actually produce a smooth open and close?
answer
- interpolation needs two blendable computed values
- a keyword has no midpoint with a length
- max-height guesses a ceiling
- fr units do interpolate
- a newer property opts keywords in
basics
~20 sA transition interpolates between two computed values of the same type, and auto is a keyword, not a length, so there is nothing to interpolate and the height jumps. Common fixes are animating max-height, animating a wrapper's grid-template-rows from 0fr to 1fr, or opting keywords in with interpolate-size.
solid answer
~50 sTransitions work by interpolating computed values, and the computed value of `height: auto` stays the keyword `auto` — it is not resolved to a pixel length at that stage. Since a length and a keyword have no midpoint, the property is treated as non-interpolable and the height simply snaps. The classic workaround is transitioning `max-height` from `0` to a value comfortably larger than the content, which works everywhere but is a guess: the extra distance is covered instantly, so the timing feels wrong. The cleaner modern CSS technique is a wrapper with `display: grid` transitioning `grid-template-rows` from `0fr` to `1fr` with `overflow: hidden` and `min-height: 0` on the child — no magic number and exact content height. As of 2026 Chromium also supports `interpolate-size: allow-keywords`, which makes `height: auto` genuinely interpolable, but it is not yet cross-browser.
code
css · 14 lines.wrapper {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 300ms ease;
}
.wrapper.open {
grid-template-rows: 1fr;
}
.wrapper > .content {
overflow: hidden;
min-height: 0;
}go deeper
Recall that height: auto cannot be transitioned and that max-height is the traditional stand-in; be able to write the overflow: hidden plus max-height pair correctly.
Explain the mechanism — a keyword computed value has no interpolable midpoint with a length — and describe the grid 0fr to 1fr technique including why min-height: 0 is required.
Weigh the options for a real component: content of unknown height, interrupted open/close, and the timing artefact a too-large max-height produces, and state which you would ship and why.
Set the direction: whether the codebase standardises one disclosure pattern, how newer CSS such as interpolate-size is adopted behind feature queries, and what degradation is acceptable in browsers without it.
## Why the transition never starts A transition needs two endpoints it can blend. The browser takes the property's computed value before the style change and after it, and asks whether the property's animation type defines an interpolation between them. For `height`, the animation type is "by computed value" over lengths and percentages. `auto` is neither: it is a keyword that survives into the computed value and is only resolved to a used pixel value later, during layout. There is no defined halfway point between `0px` and `auto`, so the property is not animated and the new value applies at once. The same reasoning explains why `width: auto`, `max-height: none`, and `display: block` historically refuse to transition. This is worth stating precisely in an interview, because the wrong explanation — "the browser doesn't know the height yet" — sounds plausible and is not the mechanism. The browser knows the height perfectly well once layout runs; the problem is that the *computed value being interpolated* is a keyword. ## Technique 1: transition `max-height` ```css .panel { overflow: hidden; max-height: 0; transition: max-height 300ms ease; } .panel.open { max-height: 500px; /* must exceed the tallest content */ } ``` Both endpoints are lengths, so this interpolates. Its drawbacks are real and interviewers look for them: you must guess a ceiling, content taller than the guess is clipped, and — because the animation runs to `500px` while the content stops at, say, `180px` — the visible part of the motion finishes early on open and appears to pause before starting on close. Enlarging the ceiling makes the timing worse, not better. ## Technique 2: grid track from `0fr` to `1fr` ```css .wrapper { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 300ms ease; } .wrapper.open { grid-template-rows: 1fr; } .wrapper > .content { overflow: hidden; min-height: 0; } ``` `0fr` and `1fr` are both `<flex>` values, so the track size interpolates, and a `1fr` row resolves to exactly the content height. There is no magic number and no clipping surprise. The `min-height: 0` on the child is required because a grid item's automatic minimum size would otherwise stop the row from shrinking below the content, and `overflow: hidden` keeps the content clipped while the row is short. ## Technique 3: `interpolate-size: allow-keywords` CSS added a way to opt into interpolating intrinsic size keywords: ```css :root { interpolate-size: allow-keywords; } .panel { height: 0; overflow: hidden; transition: height 300ms ease; } .panel.open { height: auto; } ``` `interpolate-size` is inherited, so setting it once at the root enables `auto`, `min-content`, `fit-content` and friends as transition endpoints throughout the document; internally the value is blended through `calc-size()`. As of 2026 this shipped in Chromium and is not yet available in Safari or Firefox, so treat it as progressive enhancement: browsers without it simply snap, which is an acceptable degradation. ## Technique 4: measure and set a pixel height The long-standing escape hatch is to read the content's rendered height from script, set that pixel value to start the transition, and clear it back to `auto` when the transition finishes. It is exact and works everywhere, but it moves layout knowledge into JavaScript and needs care around interrupted transitions — which is precisely why the CSS-only techniques above are preferred when they fit. ## Choosing between them If you control the wrapper markup and want exact content height today with broad support, the grid `0fr`/`1fr` technique is the strongest answer. `max-height` remains acceptable for small, bounded content such as a two-line hint. `interpolate-size` is where the platform is heading and is the right answer to "what does CSS do about this natively", with the support caveat stated. ## The general lesson The question is really about interpolability. Before reaching for a workaround, ask what the two computed values are and whether the property's animation type defines a blend between them. Length to length, colour to colour, number to number interpolate; length to keyword does not. That single test also predicts why `background-image: none` and `display: none` behave the way they do.
- Why does the grid technique need `min-height: 0` on the child?A grid item's automatic minimum size defaults to its content size, so the row refuses to shrink below the content even when the track is sized `0fr`. Setting `min-height: 0` removes that floor and lets the track collapse. `overflow: hidden` on the same element then clips the content while the row is shorter than it.
- What is visibly wrong with animating `max-height` from 0 to 1000px for 200px of content?The easing is applied across the full 1000px range, but the element stops growing at 200px. On open, the visible motion completes in roughly the first fifth of the duration and then nothing happens; on close, there is a dead pause before the panel starts moving. The bigger the safety margin, the worse it feels.
- How would you ship the `interpolate-size` approach without breaking non-supporting browsers?Treat it as enhancement. Setting `interpolate-size: allow-keywords` at the root is ignored where unsupported, and the `height: auto` change then snaps instead of easing — the panel still opens and closes correctly. If a smooth fallback matters, wrap the enhanced rules in `@supports (interpolate-size: allow-keywords)` and keep the grid technique outside it.
saying these in an interview costs you the question
- Says the browser cannot know the height, rather than naming interpolation
- Claims max-height animation is equivalent to animating height
- Believes any two values of a property can be interpolated
- Forgets overflow: hidden and min-height: 0 in the grid technique
- Presents interpolate-size as universally supported today