How To Do CSS Transitions With Height: Auto

Creating a smooth expand/collapse animation seems easy. Surely you can set a transition on height: auto, and it'll just work?

Sadly, the CSS gods aren't so kind.

Instead of the smooth open and close you wanted, your element flashes to its new height. No smooth animation.

As it turns out, animating on CSS auto values doesn't work, and it's honestly a real shame. We need to use specific values, and that's not a luxury we always have.

Fortunately, there are several approaches we can take to animating auto dimensions in CSS.

Method 1: Use transform

Despite its rampant use, you should avoid CSS transitions on the height or width properties (among some others).

These properties affect the page layout. To see how other elements on the page are being affected during your animation, the browser completely recalculates your page's layout.

For every. single. frame.

This is where the CSS transform property comes in. transform causes your element to be animated like an image, and skip the layout recalculations. If you can use this approach, you should.

Unfortunately, there are two deal-breakers in using transform to collapse your content:

  1. The content warps when it collapses.
  2. It leaves a gap where the content was.

Method 2: Animate max-height / max-width

A different approach to collapsing height is to collapse max-height in its place.

The upside of this approach is that it's straightforward. It also manages to avoid the weird warping effect of transform: scale.

There are some downsides, though:

  • We're animating on height, with all its layout-thrashing goodness
  • You need a non-auto value for max-height
  • Your transition-timing  applies to the max-height range, not height. This makes it nearly impossible to get a specific visual effect from your transitions.

Method 3: Calculate height with JavaScript

A lengthier (but more precise) approach is to use JavaScript to calculate the animation start and end using the element's rendered height.

Once we determine the element's actual height, we can inject it as inline CSS so the browser has something to transition between.

In terms of effect, this is probably the one you were going for, but with tradeoffs.

  • We're still animating on height
  • We've introduced a fair chunk of code to address a very narrow problem
  • There's tight coupling between your JavaScript and CSS

Method 4: Nuke from orbit with FLIP + Inverse Scaling

Remember Method 1 and all the problems that using transform caused?

Well, it turns out you can fix them.

Content warping can be fixed by applying counter-scaling on your content. The FLIP technique also lets us move surrounding content in a performant way.

This looks much better than our initial transform attempt, and solves the problems we were having. However:

  • This solution is big and complex. We've introduced a lot of code now, and it's still a very narrow problem.
  • Several moving parts need to stay synchronised
  • We need a custom easing function. I've used linear for simplicity, but anything else gets gnarly.
  • Even more coupling than the height example.

Can't get past JavaScript Tutorials?

Download my FREE ebook on how to succeed as a self-taught JavaScript Developer, and how to find projects that you'll actually finish. Learn More...

Read more