CSS & Layout
The classic wall: you can't CSS-transition to height: auto. A one-line CSS Grid trick gets you a smooth open-and-close to the content's natural height — no measuring, no script.
Live Result
Click the header to toggle — the panel glides open and shut to fit its text, with no fixed height set anywhere.
<div class="accordion">
<input type="checkbox" id="acc" checked>
<label class="acc-head" for="acc">
What's included? <span class="chev">›</span>
</label>
<!-- This wrapper is what we animate -->
<div class="acc-body">
<div class="acc-inner">
<p>Strategy session, custom design, and a hand-built
front end. The panel below grows to fit whatever
content lives inside it — no fixed height, no
JavaScript measuring anything.</p>
</div>
</div>
</div> .acc-body {
display: grid;
/* Collapsed: the row has zero height... */
grid-template-rows: 0fr;
transition: grid-template-rows .35s ease;
}
/* ...open: the row expands to its content's natural height */
.accordion input:checked ~ .acc-body {
grid-template-rows: 1fr;
}
/* A grid item can't go below its content size unless its
overflow is hidden — this is the piece that makes 0fr work */
.acc-inner {
overflow: hidden;
} Browsers refuse to animate between a pixel height and height: auto, because they don't know the end value until layout runs. For years the workarounds were ugly: hard-code a max-height and hope your content never exceeds it, or measure the element in JavaScript and animate to that number.
CSS Grid sidesteps the whole problem. A grid row sized in fr units does interpolate smoothly. So we wrap the content in a single-row grid and transition that row from 0fr (zero share of the height) to 1fr (all of it). The browser is animating a flexible track, not an auto value, so it knows exactly what to tween between.
The one piece people miss: the inner element needs overflow: hidden. Without it, a grid item won't shrink below the size of its own content, so the 0fr row never actually collapses. With it, the content gets clipped as the track closes — giving you the clean reveal.
Here the toggle is a hidden checkbox driving a sibling selector, so the whole thing stays pure CSS and keyboard-accessible. Swap the checkbox for a class you toggle in JS if you'd rather control it from code — the animating CSS is identical either way.
Animating an element to its natural height has long needed JavaScript or fixed heights. This example uses a CSS grid row transition from 0fr to 1fr so a panel opens smoothly to whatever size its content is.
Use it for accordions, FAQ lists, expandable cards, and any panel whose height changes with its content. It stays accessible and keeps your scripts lighter.
Related: All code examples · Scroll-reveal example · Web design services