The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| 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 content | if (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
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.
.accordion { interpolate-size:allow-keywords; }
.panel { height:0; overflow:clip; transition:height .25s ease; }
details[open] .panel { height:auto; } 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.
.drawer { block-size:0; transition:block-size .25s; }
.drawer.open { block-size:calc-size(auto, size + 1rem); } 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.
.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; } } 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.
.faq-item { contain:layout; }
.faq-panel { overflow:clip; }
@media (prefers-reduced-motion:no-preference) { .faq-panel { transition:block-size .22s ease-out; } } 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 aria-expanded="false" aria-controls="faq-panel">Build requirements</button>
<div id="faq-panel" class="panel" hidden>Node.js 22 or newer.</div> 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.
.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; } } 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.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
- CSS Working GroupCSS Values and Units Module Level 5drafts.csswg.org
- CSS Working GroupCSS Box Sizing Module Level 4drafts.csswg.org
- CSS Working GroupCSS Transitions Level 2drafts.csswg.org
- WHATWGHTML Living Standard: The details elementhtml.spec.whatwg.org
- Web Accessibility InitiativeUnderstanding Success Criterion 2.3.3: Animation from Interactionsw3.org
- MDN Web Docsinterpolate-sizedeveloper.mozilla.org
- 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.



