Search code examples
javascripthtmlcssanimationtransition

How to force transition animation for properties not yet defined on the element?


I have this code:

    var c = document.getElementById('container');

    function expand() {
        c.style.maxHeight = ~~(Math.random() * 50 + 50) + 'px'; // it can be any value
        // Since the value is dynamic, static solutions (like CSS Animations) are not allowed
    }

    function shrink() {
        c.style.maxHeight = '0px';
    }
    .container {
        transition: max-height 1s ease;
        border: 1px solid #000;
        overflow: auto;
    }
<div id="container" class="container">Hello, World!<br />Hello, World!<br />Hello, World!<br />Hello, World!<br />Hello, World!<br /></div>

<input type="button" onclick="expand()" value="Expand" />
<input type="button" onclick="shrink()" value="Shrink" />

When I click the "Shrink" button, the container instantly goes to 0px height. Since the property "maxHeight" is not set yet, the animation hasn't both start/end parameters to perform the transition. After I click either button, the animation runs normally.

I can bypass this issue presetting the property if it's not set yet, but I need to use setTimeout and lambda functions, what is way overcomplicated to the simplicity I'm looking for.

Also, I cannot add the style='maxheight=xxx' property on each element because this function manages elements on third party code, which I cannot alter.

So, how can I properly perform this animation?


Solution

  • You can force a reflow right after you set the initial value, and right before you trigger the change:

    var c = document.getElementById('container');
    
    function expand() {
      c.style.maxHeight = ~~(Math.random() * 50 + 50) + 'px'; // it can be any value
    }
    
    function shrink() {
      c.style.maxHeight = c.offsetHeight + "px";
      c.offsetHeight; // force reflow
      c.style.maxHeight = '0px';
    }
    .container {
      transition: max-height 1s ease;
      border: 1px solid #000;
      overflow: auto;
      resize: both;
    }
    <div id="container" class="container">Hello, World!<br />Hello, World!<br />Hello, World!<br />Hello, World!<br />Hello, World!<br /></div>
    
    <input type="button" onclick="expand()" value="Expand" />
    <input type="button" onclick="shrink()" value="Shrink" />