Command Palette

Search for a command to run...

Hectal
Shots in this scene
SHOT 10.4Intermediate ~19 min · shot 4 of 6

Animating to height: auto

In one line

CSS cannot blend a length with the keyword auto, so a panel that opens to its natural height snaps. interpolate-size: allow-keywords, calc-size() and the 0fr to 1fr grid trick fix that, and ::details-content makes <details> accordions animate.

0/6 · 0%

Think of it like this

An accordion door in a hall. You want it to open exactly as wide as the room behind it needs. You cannot say "slide open by 'as much as it takes'" to a motor that only understands centimetres. You must either measure the room or give the motor a rule that knows about rooms.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

interpolate-size
An inherited property. allow-keywords lets the browser blend intrinsic sizes such as auto with lengths.
calc-size()
A function that lets you do maths on an intrinsic size, such as calc-size(auto, size + 20px).
fr
A grid unit meaning a share of the free space. 0fr is zero and 1fr is all of it.
::details-content
A pseudo-element for the box around the content of a <details> element.
intrinsic size
A size the content decides (auto, min-content, max-content), rather than a number you wrote.

Step by step

01Check support

Run "Three ways to open a panel". The console prints interpolate-size: true, calc-size(): true and ::details-content: true in this editor's browser.

02Open all three

Press Open / close all three. The first panel is at its full 29 px at 0 ms: no track, no motion. The second and third grow over 500 ms (about 19.8 px at 250 ms). Their tracks are height and grid-template-rows, both red.

03Add a line while open

Open them, wait, and press Add a line to each. All three jump from 29 to 58 px at once: nothing was animating, because no style changed.

04Use details

In "An accordion with ::details-content" press Battery, then Motor, and close Motor half way: it turns round smoothly from where it is, because it is an ordinary transition that reverses.

Try it yourself

  1. 1

    Swap in calc-size()

    In the first example remove interpolate-size: allow-keywords; from .b and change .b.open { height: auto; } to .b.open { height: calc-size(auto, size + 20px); }. After Run, press the button: the second panel still animates and ends at 49 px (29 + 20), 33.5 px at 250 ms.

  2. 2

    Switch on reduced motion

    Turn on Reduced motion in the timeline and press the button: the second panel still slides, because the CSS has no reduce rule. Add @media (prefers-reduced-motion: reduce) { .b, .c { transition: none; } } and run again: it snaps.

  3. 3

    Reverse in the middle

    In the details example open Motor, then click it again about 200 ms later (the timeline cannot step this one, so click quickly in real time). The height turns round from where it is and walks back to its closed height. No jump.

Code & diagrams

Three ways to open a panel

The first panel has no help and snaps. The second uses interpolate-size and the third the grid trick. Pause at 250 ms and read the heights.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.

Expected console output

interpolate-size: true
calc-size(): true
::details-content: true
An accordion with ::details-content

The same pattern the project's specs use, with a nested section. In a browser without ::details-content the sections simply snap open.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.

Expected console output

sections: 3

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Take interpolate-size away

In the details example delete :root { interpolate-size: allow-keywords; }.

terminal
$ Open Battery
── what you'll see ──
Measured with timers in the page (the timeline cannot list `::details-content` transitions): the Battery section is at its full height, 103 px with its nested section, on the next frame. With the rule in place it climbs from 33 px to 103 px over about 400 ms.

Myth vs fact

Myth

You need JavaScript to animate height: auto.

Fact

Three CSS-only ways exist today. Measuring scrollHeight and animating to a pixel value was the old way, and it breaks when the content changes.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    interpolate-size inherits, so putting it on :root turns it on for the whole page. Some teams prefer to turn it on per component, because intrinsic-size animations are layout work.

  • ▸

    block-size is the logical twin of height: it follows the writing mode, so the same rule works for vertical text. That is why the ::details-content pattern uses it.

  • ▸

    Test with @supports not selector(::details-content) to put a note or a different style in browsers that lack it. The example shows the pattern in its last rule.

Remember this

  1. 1

    The problem this solves: a transition needs two numbers to blend. height: 0 is a number. height: auto is a keyword that means "whatever the content needs", so the browser has nothing to blend and applies the end value at once. Accordions, menus and expanding cards all hit this.

  2. 2

    **interpolate-size: allow-keywords.** Set it on :root (the property inherits) and the browser resolves auto, min-content, max-content and fit-content to pixels at the moment it starts the transition, so height: 0 to height: auto animates. Chrome 129 shipped it. In the example, the second panel does this and the first panel, without it, snaps.

  3. 3

    **calc-size().** height: calc-size(auto, size) is a function that wraps the keyword so it can be used in maths: calc-size(auto, size + 20px) is the content height plus 20 px. A calc-size() value interpolates on its own without interpolate-size. MDN (checked on 22 October 2026) lists calc-size() as limited availability and not Baseline: use it as an enhancement.

  4. 4

    The grid trick, for every browser. Put the content in a grid whose row goes from 0fr to 1fr, and give the inner wrapper overflow: hidden; min-height: 0. Grid tracks interpolate, and 1fr of a single row is the content's height. No JavaScript and no measuring. It works wherever grid-template-rows transitions work, which is every current browser.

  5. 5

    Every one of them costs layout. The timeline shows height and grid-template-rows as red tracks: each frame the page is laid out. That is fine for one short accordion and bad for 100 of them at once. A FLIP of the content below (Topic 10.1) is the compositor-only alternative.

  6. 6

    **<details> and ::details-content.** The browser hides a closed <details> content with content-visibility: hidden, which cannot be animated by height. The ::details-content pseudo-element is a box around that content: give it block-size: 0 closed and auto open, plus content-visibility with allow-discrete, and the accordion slides. MDN lists ::details-content as Baseline newly available since September 2025 (checked 22 October 2026). The Phase 10 build uses it. One limit of our tools: in Chromium 153 these transitions run but are not listed by getAnimations(), so the timeline cannot show, pause or step them. Measure them with timers in the page.

  7. 7

    Fallbacks. A browser without interpolate-size still ends up correct: height: auto applies at once, so the panel opens without sliding. Write the rule so the snapped state is the working state, put the animation on top, and test with @supports (interpolate-size: allow-keywords) where the layout relies on it.

  8. 8

    Content that changes while open. If a line is added to an open panel, no style changed, so nothing transitions: the panel jumps to its new height. Reduced motion needs its own rule too: in the example, switching it on changes nothing until you add a reduce rule.

Explain it without notes

01

Why can't CSS animate height: 0 to height: auto by default, and what does interpolate-size change?

02

When would you use the grid trick instead of interpolate-size?

Practice

01

Write the CSS and HTML for a FAQ item that opens with the grid trick.

02

A card shows 3 lines of text and a "Read more" button that shows all of it. How do you animate it with interpolate-size?

Trade-offs

  • ↔

    Height animations cost layout on every frame. Prefer them for one or two small panels; for big lists, animate the siblings with FLIP.

Done when you can

  • You can explain why auto snaps

  • You can use interpolate-size, calc-size() and the grid trick

  • You can animate a <details> with ::details-content

  • You can say what happens when the content changes while open