CSS Hack! Animate Height from 0 to Auto

A common desire in web development is animating an expandable element height from a value of 0 to auto (accordion, dropdown, etc.). I.e. We want text to be completely collapsed until a user hovers over something at which point the text expands to reveal itself at its natural length. The text should flow correctly for the container and screen size without anything getting cutoff.

So, here's the scoop according to the tech gurus over at Mozilla Developer Network: 'auto' values got left out from the CSS transitions spec. Now, you might wonder, "Why on earth would they do that?" Truth is, a handful of folks have been scratching their heads over the same thing.

Here's the thing though - it's not without reason. You see, there's this nifty (yet quite power-hungry) process the browser does called 'reflow'. Basically, it's the browser’s way of figuring out the sizes and positions of all elements. It takes into account their content, and how they all interact with each other.

Now, let's say you want an element to transition to a height of 'auto'. Our dear browser would need to pause and perform a reflow at every single stage of the animation, just to determine how the rest of the elements should adjust. That's quite the computational hiccup!

Moreover, the problem gets bigger because the browser doesn’t know the starting and ending values until the transition actually kicks off. This throws in a curveball into the already complex math happening behind the scenes, and could bog down performance in a way that might slip right under a developer's radar.

So, all things considered, it does make a certain amount of sense that 'auto' values were left out in the cold when it came to CSS transitions.

Javascript can do it... but what if we still want to use our beloved CSS? Added benefit in Webflow is that we see the behavior right there in designer! Since CSS runs off of the main thread, we could realize some performance benefit as well!

There have been a number of workarounds to solve the issue, but all of them have a drawback we should highlight. I won't detail them here beyond a mention:

  1. Max-height - Problems are that you may not be able to GUARANTEE that your height will have some maximum. Will the client change things up on you? Will you test this transition extensively on every breakpoint? Subtly, the animations may look a bit off with max-height because the timing will be programmed for the max-height value, and not the actual text height value. If your heights aren't the same across the board, it looks weird.
  2. transform: scaleY() - The most exciting bit is that using transform doesn’t trigger a reflow, just like a carefree artist who only cares about the "picture" rather than the layout of the gallery. It's neat as it allows you to toggle between fully visible and invisible without disrupting the rest of the elements. However, be warned - it's picky! It works like a charm for floating elements, like modals or tooltips, or the ones at the very bottom of the page. But for many situations, it might just give you the cold shoulder and simply not work.
  3. Javascript - This is the solution I've found to be most effective, but requires additional code lines, careful monitoring of style changes, and potentially causes transition conflicts or sync issues.

On with the show.

Here's the CSS that doesn't work:

.thing-to-animate {
  height: 0;
  transition: height 0.5s ease-out;
}

.thing-to-animate.open {
  height: auto;
}

Now let's use grid-template-rows and fix that!

.wrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.5s ease;
}

.wrap.open {
  grid-template-rows: 1fr;
}

.content {
  overflow: hidden;
}
<div class="wrap">
  <div class="content">Here be the content to animate on expand.</div>
</div>

This technique is much tidier, requiring only two DOM nodes and causing the page content below to move smoothly. Just bear in mind, you can't add padding to the inner element. If padding is needed, you'll need an additional element inside the collapsed one to apply it to.



Watch the Tutorial on YouTubeGet the Project Cloneable

Inside <head> tag

Inside </body> tag