The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Enable keyword interpolation.disclosures { interpolate-size: allow-keywords; }View examples
Restore default behavior.no-intrinsic-motion { interpolate-size: numeric-only; }View examples
Transition height to auto.panel { height:0; transition:height .25s; } .panel.open { height:auto;; }View examples
Transition to max-content.label { width:8rem; transition:width .2s; } .label:hover { width:max-content;; }View examples
Animate flex-basis content.item { flex-basis:4rem; } .item.open { flex-basis:content;; }View examples
Pass through auto.panel { height:calc-size(auto, size); }View examples
Add to an intrinsic size.panel { height:calc-size(auto, size + 2rem); }View examples
Scale a fit-content size.tag { width:calc-size(fit-content, size * .8); }View examples
Round an intrinsic result.menu { width:calc-size(max-content, round(up, size, 2rem)); }View examples
Gate intrinsic interpolation@supports (interpolate-size: allow-keywords) { .panel { transition: height .25s; }; }View examples
Gate intrinsic calculation@supports (height: calc-size(auto, size)) { .panel { height: calc-size(auto, size); }; }View examples
Use a broad disclosure fallback.content { display:grid; grid-template-rows:0fr; } .open .content { grid-template-rows:1fr;; }View examples
Skip closed content.closed { content-visibility:hidden; }View examples
Limit layout propagation.component { contain:layout; }View examples
Clip the animated reveal.panel { overflow:clip; }View examples
Disable intrinsic transitions@media (prefers-reduced-motion: reduce) { .panel { transition:none; }; }View examples
Use native disclosure markup<details><summary>Release notes</summary><div class="panel">Content</div></details>View examples
Avoid hiding focused contentif (panel.contains(document.activeElement)) summary.focus();View examples
Test intrinsic changes during loading.panel { max-inline-size: 100%; overflow-wrap: anywhere; }View examples

Intrinsic sizing keywords historically animate discretely because their used lengths depend on layout. interpolate-size opts a subtree into interpolation between a length-percentage and a supported intrinsic keyword, while calc-size() represents calculations based on one intrinsic size. Both features are evolving, inherited or context-sensitive, and layout-intensive, so this guide starts with usable disclosure patterns and treats smooth intrinsic animation as enhancement.

Step by step

Detailed examples

01

Opt in narrowly because the property inherits

interpolate-size accepts numeric-only or allow-keywords and inherits. allow-keywords enables interpolation between a length-percentage and supported intrinsic values such as auto, min-content, max-content, fit-content, and content in applicable contexts. It does not generally interpolate between two different intrinsic keywords. Scope the opt-in to the component tree instead of :root when third-party widgets could acquire unexpected transitions.

Scoped height-to-auto transition
.accordion { interpolate-size:allow-keywords; }
.panel { height:0; overflow:clip; transition:height .25s ease; }
details[open] .panel { height:auto; }
Back to quick reference ↑
02

Calculate from exactly one intrinsic basis

calc-size(basis, calculation) introduces size as the resolved basis inside a calculation. The result remains an intrinsic size and is interpolable; using calc-size() effectively opts that value into keyword interpolation. It can add, scale, clamp, or round one basis, but cannot meaningfully subtract max-content from min-content. Use interpolate-size for ordinary length-to-keyword transitions and reserve calc-size() for a genuinely modified endpoint.

Intrinsic endpoint plus design spacing
.drawer { block-size:0; transition:block-size .25s; }
.drawer.open { block-size:calc-size(auto, size + 1rem); }
Back to quick reference ↑
03

Make open and closed states correct without animation

These features have evolving support. The baseline should show all open content and hide closed content using native details, hidden, or application state. Put new declarations inside precise @supports blocks. A 0fr-to-1fr grid-track pattern can provide a broader visual enhancement but needs an inner min-block-size:0 wrapper and is not identical to intrinsic height interpolation. Avoid fixed max-height tricks that distort duration and clip large translations.

Native baseline with layered enhancement
.panel { display:block; }
details:not([open]) .panel { display:none; }
@supports (interpolate-size:allow-keywords) { details:not([open]) .panel { display:block; height:0; overflow:clip; } details[open] .panel { height:auto; } }
Back to quick reference ↑
04

Expect layout work during every sampled size

Animating width, height, or flex-basis changes layout and can reflow descendants and siblings each frame. Containment can limit propagation but also changes containing blocks, margin behavior, and intrinsic contribution. Clip overflow so intermediate content does not leak, avoid huge subtrees, and profile on low-end hardware. Transforms are cheaper when a visual scale is acceptable, but scaling text can blur and does not move following content.

Localize the expensive reveal
.faq-item { contain:layout; }
.faq-panel { overflow:clip; }
@media (prefers-reduced-motion:no-preference) { .faq-panel { transition:block-size .22s ease-out; } }
Back to quick reference ↑
05

Preserve disclosure semantics and focus

CSS size changes do not create expanded state or keyboard behavior. Start with details/summary or a button with aria-expanded and aria-controls synchronized by JavaScript. Content at zero height can remain focusable unless it is also hidden or inert, so coordinate interactivity with the closed state. Before collapsing, move focus to the controller if focus is inside. Reduced-motion users should receive an immediate state change, not a slower alternative.

Button disclosure contract
<button aria-expanded="false" aria-controls="faq-panel">Build requirements</button>
<div id="faq-panel" class="panel" hidden>Node.js 22 or newer.</div>
Back to quick reference ↑
06

Test content mutation and every sizing constraint

Intrinsic endpoints can change while fonts, images, localization, validation messages, or async content load. Test opening during those changes, rapid reversal, nested disclosures, writing modes, zoom, long content, min/max sizes, overflow, and resize. @supports detects syntax, not smoothness or performance. Verify transition events are not required for correctness because reduced motion, zero duration, interruption, or display changes can prevent expected events.

Enhance only motion, never correctness
.panel { max-inline-size:100%; overflow-wrap:anywhere; }
@supports (interpolate-size:allow-keywords) { .component { interpolate-size:allow-keywords; } }
@media (prefers-reduced-motion:reduce) { .panel { transition:none; } }
Back to quick reference ↑

Local code tester

Enhance a native disclosure with intrinsic sizing

Open the details element to compare an accessible baseline with a scoped height-to-auto transition; reduced-motion preferences make it immediate.

Runs in your browser
Preview

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. CSS Working GroupCSS Values and Units Module Level 5drafts.csswg.org
  2. CSS Working GroupCSS Box Sizing Module Level 4drafts.csswg.org
  3. CSS Working GroupCSS Transitions Level 2drafts.csswg.org
  4. WHATWGHTML Living Standard: The details elementhtml.spec.whatwg.org
  5. Web Accessibility InitiativeUnderstanding Success Criterion 2.3.3: Animation from Interactionsw3.org
  6. MDN Web Docsinterpolate-sizedeveloper.mozilla.org
  7. MDN Web Docscalc-size()developer.mozilla.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback