Question: CSS transition doesn't animate when immediately changing size via JavaScript

Question

CSS transition doesn't animate when immediately changing size via JavaScript

Answers 3
Added at 2016-12-31 12:12
Tags
Question

When setting the height of an element to 0 in JavaScript and then immediately changing it to a specific value, the CSS transition for the element doesn't work.

However, by placing the code to increase the height inside a setTimeout(), even with a delay of 0, the transition works, as you can see in the following snippet:

// Doesn't work:
document.getElementById("one").setAttribute("style", "height: 0px");
document.getElementById("one").setAttribute("style", "height: 200px");

// Works:
document.getElementById("two").setAttribute("style", "height: 0px");
setTimeout(function() {
	document.getElementById("two").setAttribute("style", "height: 200px");
}, 0);
div {
  display: inline-block;
  width: 200px;
  background-color: black;
  transition: height 1s;
}

#two {
  background-color: blue;
}
<div id="one">
</div>
<div id="two">
</div>

This behavior is consistent across all major browsers. The problem with this is, that sometimes, there seems to be some kind of lag, which makes the workaround not animate as well. So this doesn't seem to be a clean solution.

What causes the transition to cancel and how can I get around this cleanly?

Answers
nr: #1 dodano: 2016-12-31 12:12

Most likely browsers optimize transitions and will merge changes which take less than 16ms (which would get you a refresh rate of about 60 frames per second)

So the solution is to simply wrap style changes nested RAF calls (tell the browser to animate when it's ready rather than after an arbitrary timeout)

window.requestAnimationFrame(function(){
document.getElementById("two").setAttribute("style", "height: 0px");
 window.requestAnimationFrame(function(){
    document.getElementById("two").setAttribute("style", "height:  200px");
  });
});

reference: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame

nr: #2 dodano: 2016-12-31 12:12

Try adding it to the window.onload event

window.addEventListener("load", init, false);

function init() {
    document.getElementById("one").style.height = "200px";
}

also you gonna have to set #one height in CSS to 0

#one {
   height:0px;
}
nr: #3 dodano: 2016-12-31 13:12
//cache the object in a variable
var one = document.getElementById("one");

//do you really need to overwrite all stlyles defined on this object?
//if not, prefer style-property over attribute
//set animation-start
one.style.height = 0;

//force the browser to apply styles
getComputedStyles(one);

//apply the animation-target
one.style.height = "200px";

You don't need any timeout, but beware, this forces the browser into a render-cycle (one of the most expensive things one could do in JS).

So don't use this in a loop (or on multiple nodes, one after the other). But instead do two loops, first set all the start-values, force the browser into the render-cycle, and then apply all the target-values.

Source Show
◀ Wstecz