CSS-only animated accordion with dynamic content height

Blog / CSS3 ·
CSS-only animated accordion with dynamic content height

CSS became more powerful over the years, allowing developers to create interactive components without relying on JavaScript. One such component is an animated accordion that smoothly expands and collapses content sections. In this article, we'll explore how to create a CSS-only animated accordion that dynamically adjusts its height based on the content inside.

The problem

Creating an accordion with CSS alone can be challenging, especially when it comes to animating the height of the content area. The height property in CSS cannot transition from 0 to auto, or fit-content which is necessary for dynamic content heights. Consider the following markup:

<div class="accordion">
  <input type="checkbox" id="accordion-box"/>
  <label for="accordion-box">
    CSS stands for Cascading Style Sheets.
  </label>
  <div class="content">
    <p>... long text here ...</p>
  </div>
</div>

The idea is that the .content div should expand and collapse when the checkbox is toggled.

.accordion [type="checkbox"] {
  position: absolute;
  opacity: 0;
  z-index: -1;
}
.accordion [type="checkbox"] + label {
  cursor: pointer;
}
.accordion [type="checkbox"]:checked ~ .content {
  /* do some magic here */
}

Since the label is properly linked to the checkbox, clicking on it will toggle the checkbox state. And by using :checked pseudo-class, we can target the .content div to show or hide it. However, animating the height of .content from 0 to auto is not possible directly. For example this does not work:

.accordion .content {
  height: 0;
  overflow: hidden;
  transition: height 0.35s ease;
}
.accordion [type="checkbox"]:checked ~ .content {
  height: auto; /* This won't animate */
}

The neat solution

To achieve a smooth height transition for dynamic content, we can use CSS Grid's grid-template-rows property. By defining the content area as a grid row, we can animate the row height from 0 to 1fr, which allows the content to take up the necessary space.

.accordion .content {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  transition: grid-template-rows 0.35s ease;
}
.accordion [type="checkbox"]:checked ~ .content {
  grid-template-rows: 1fr;
}

That's weird but it works. Here's a CodePen demo:

See the Pen Untitled by Krasimir Tsonev (@Krasimir-Tsonev) on CodePen.


Krasimir Tsonev With over two decades of deep programming expertise, I offer comprehensive web consultancy and stack audits, alongside specialized workshops, training, and engaging public speaking to elevate your team's skills and optimize your digital presence. Contact me.

Keywords: css tips
Share the post on Twitter, Facebook, LinkedIn