I cannot find a way to use css transitions on newly created dom elements.
let's say I have an empty html document.
<body>
<p><a href="#" onclick="return f();">click</a></p>
</body>
I also have this css
#id {
-moz-transition-property: opacity;
-moz-transition-duration: 5s;
opacity: 0;
}
#id.class {
opacity: 1;
}
and this js
function f() {
var a = document.createElement('a');
a.id = 'id';
a.text = ' fading in?';
document.getElementsByTagName('p')[0].appendChild(a);
// at this point I expect the span element to be with opacity=0
a.className = 'class';
// now I expect the css transition to go and "fade in" the a
return false;
}
but, as you can see on http://jsfiddle.net/gwxkW/1/ when you click the element appears instantaneously.
If I try to set the class in a timeout()
i often find the result, but to me it seems more a race between javascript and the css engine. Is there some specific event to listen? I tried to use document.body.addEventListener('DOMNodeInserted', ...)
but it's not working.
How can I apply css transitions on newly created elements?
In Firefox, it does appear to be a race between layout completing and the CSS transition. Chrome is much more predictable. If I set the class name on a setTimeout()
, Chrome always works, Firefox only works if the setTimeout()
time is long.
With this code in Firefox (even using the setTimeout()
), the text shows immediately:
function f() {
var a = document.createElement('a');
a.id = 'id';
a.innerHTML = ' fading in?';
document.getElementsByTagName('p')[0].appendChild(a);
// at this point I expect the span element to be with opacity=0
setTimeout(function() {
a.className = 'fadeIn';
}, 10);
return false;
}
But, if I force a reflow by requesting a property that can only be returned after layout, it then starts to work in Firefox:
function f() {
var a = document.createElement('a');
a.id = 'id';
a.innerHTML = ' fading in?';
document.getElementsByTagName('p')[0].appendChild(a);
// at this point I expect the span element to be with opacity=0
// request property that requires layout to force a layout
var x = a.clientHeight;
setTimeout(function() {
a.className = 'fadeIn';
}, 10);
return false;
}
Furthermore, once I've request that property to force a layout, I can even remove the setTimeout()
and the animation works in Firefox.
function f() {
var a = document.createElement('a');
a.id = 'id';
a.innerHTML = ' fading in?';
document.getElementsByTagName('p')[0].appendChild(a);
// at this point I expect the span element to be with opacity=0
// request property that requires layout to force a layout
var x = a.clientHeight;
a.className = 'fadeIn';
return false;
}
You can see this last one work here in both Chrome and Firefox: http://jsfiddle.net/jfriend00/phTdt/
And, here's an article that discusses the phenomenon: http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html