← Code Examples

CSS & Layout

Animate to height: auto, With No JavaScript

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.

index.html
<div class="accordion">
  <input type="checkbox" id="acc" checked>
  <label class="acc-head" for="acc">
    What's included? <span class="chev">&rsaquo;</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>
style.css
.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;
}

Why this works

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.