We’ve all been there. You’ve got an element you want to be able to collapse and expand smoothly using CSS transitions, but its expanded size needs to be content-dependent. You’ve set
transition: height 0.2s ease-out
. You’ve created acollapsed
CSS class that appliesheight: 0
. You try it out, and… the height doesn’t transition. It snaps between the two sizes as iftransition
had never been set. After some fiddling, you figure out that this problem only happens when the height starts out or ends up asauto
. Percentages, pixel values, any absolute units work as expected. But all of those require hard coding a specific height beforehand, rather than allowing it to naturally result from the size of the element content.[…]
If you were hoping I had a magical, complete solution to this problem, I’m sorry to disappoint you. There’s no one solution that achieves the desired effect without downsides. There are, however, multiple workarounds that each come with a different set of advantages and disadvantages, and in most use cases at least one of them will get the job done in an acceptable manner. I’ll outline the major ones, and list out their ups and downs so you can hopefully pick the best one for your situation.
[…]
Technique 1:
max-height
If you web search this problem, the
max-height
approach will probably be mentioned in all of the first five to ten results. It’s actually pretty unideal, but I thought it was worth including here for the sake of comparison.It works like this: CSS values can only be transitioned to and from fixed unit values. But imagine we have an element whose
height
is set toauto
, but whosemax-height
is set to a fixed value; say,1000px
. We can’t transitionheight
, but we can transitionmax-height
, since it has an explicit value. At any given moment, the actual height of the element will be the maximum of theheight
and themax-height
. So as long asmax-height
’s value is greater than whatauto
comes out to, we can just transitionmax-height
and achieve a version of the desired effect.[…]
Technique 2:
transform: scaleY()
[…]
Implementation works like this: we set a
transition
for the element’stransform
property, then toggle betweentransform: scaleY(1)
andtransform: scaleY(0)
. These mean, respectively, “render this element at the same scale (on the y axis) that it starts out at” and “render this element at a scale of 0 (on the y axis)”. Transitioning between these two states will neatly “squish” the element to and from its natural, content-based size.Technique 3: JavaScript
Managing a CSS transition in CSS would be ideal, but as we’re learning, sometimes it just isn’t entirely possible.
If you absolutely have to have smoothly collapsing sections, whose expanded size is completely driven by their content, and which other elements on the page will flow around as they transition, you can achieve that with some JavaScript.
The basic strategy is to manually do what the browser refuses to: calculate the full size of the element’s contents, then CSS transition the element to that explicit pixel size.