A Lazy Sequence

Triggering CSS transitions on new elements

CSS transitions are a great alternative to programming a lot of trivial animations by hand in Javascript. Programatically the completion of a transition can be captured by the transitionend. I recently ran into an awkward edge case where I wanted to add a DOM element to a document, and immediately trigger a transition. For example:

// the following assumes that a transition rule exists for 
// the 'left' property. left defaults to 0.

var node = document.createElement("div");
node.className = "transitionable";
node.addEventListener("transitionend", function () { 
    console.log("transition done!"); 
});

document.body.appendChild(node);
node.style.left = "200px"; 

The above worked fine for me in Safari and Chrome, but failed in Firefox. After some experimentation it appears to be a race between the CSS style being computed initially on insertion, and Javascript that changes the style being executed. If the Javascript runs first, then no transition occurs as the CSS engine does not see any change.

The solution that worked for me (suggested by Firefox developer Boris Zbarsky) is to flush the DOM and CSS using getComputedStyle.

var node = document.createElement("div");
node.className = "transitionable";
node.addEventListener("transitionend", function () { 
    console.log("transition done!"); 
});

document.body.appendChild(node);

// force the current style to be calculated
void window.getComputedStyle(node, null)
           .getPropertyValue("left");

node.style.left = "200px"; 

This code works as expected, and I can now use the transitionend reliably. The void keyword to indicate to the reader that the value is being intentionally discarded.

Full examples of both cases can be found in this gist.

Postscript

Discussion on the Firefox bug tracker suggests that this behaviour is according to the specification and therefore is not going to change.

17 September 2013