const animatable = document.getElementById('animatable'); document.getElementById('reset').addEventListener('click', event => { animatable.removeAttribute('style'); }); document.getElementById('broken').addEventListener('click', event => { animatable.style.height = 0; animatable.classList.add('mod-open'); animatable.style.height = '100px'; }); document.getElementById('working-prop').addEventListener('click', event => { animatable.style.height = 0; animatable.classList.add('mod-open'); // This stops the render engine so that height and the class are applied animatable.clientHeight; animatable.style.height = '100px'; }); document.getElementById('working-task').addEventListener('click', event => { animatable.style.height = 0; animatable.classList.add('mod-open'); // This stops the render engine so that height and the class are applied setTimeout(() => { animatable.style.height = '100px'; }, 0); });
<div id="animatable"></div> <div> <button id="reset"> Reset </button> <button id="broken"> Run broken </button> <button id="working-prop"> Run working property </button> <button id="working-task"> Run working micro task </button> </div>
#animatable { background: red; width: 100px; } .mod-open { transition: height .5s linear; }