I have an svg with transitions set on it. Now when I add a class to it which has some properties varied then the transition only occur if I add delay between DOMContentLoaded event and addclass event. Here are two example, first with no delay second with an infinitesmall delay:
Without Delay:
! function() {
window.addEventListener('DOMContentLoaded', function() {
var logo2 = document.querySelector("svg");
logo2.classList.add('start');
});
}();
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 104.75 32.46">
<defs>
<style>
polygon {
fill: red;
transition: opacity 3s ease-out, transform 3s ease-out;
opacity: 0;
}
.start polygon {
opacity: 1;
}
#A1 polygon {
transform: translate(100px, 100px);
transition-delay: 1s;
}
/*styles after animation starts*/
.start #A1 polygon {
transform: translate(0px, 0px);
}
</style>
</defs>
<title>Logo</title>
<g id="A1">
<polygon class="right" points="0.33 31.97 0.81 26.09 13.61 3.84 13.13 9.72 0.33 31.97" />
</g>
</svg>
With Delay:
! function() {
window.addEventListener('DOMContentLoaded', function() {
var logo2 = document.querySelector("svg");
setTimeout(function(){
logo2.classList.add('start');
},0);
});
}();
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 104.75 32.46">
<defs>
<style>
polygon {
fill: red;
transition: opacity 3s ease-out, transform 3s ease-out;
opacity: 0;
}
.start polygon {
opacity: 1;
}
#A1 polygon {
transform: translate(100px, 100px);
transition-delay: 1s;
}
/*styles after animation starts*/
.start #A1 polygon {
transform: translate(0px, 0px);
}
</style>
</defs>
<title>Logo</title>
<g id="A1">
<polygon class="right" points="0.33 31.97 0.81 26.09 13.61 3.84 13.13 9.72 0.33 31.97" />
</g>
</svg>
As you can see in second example I added a delay of 0 second but it caused the animations to work, why?
Update1: well... we all are wrong :-)
I tried the same code without DOMContentLoaded
and without delay. It still doesn't add transition without a delay:
! function() {
var logo2 = document.querySelector("svg");
logo2.classList.add('start');
}();
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 104.75 32.46">
<defs>
<style>
polygon {
fill: red;
transition: opacity 3s ease-out, transform 3s ease-out;
opacity: 0;
}
.start polygon {
opacity: 1;
}
#A1 polygon {
transform: translate(100px, 100px);
transition-delay: 1s;
}
/*styles after animation starts*/
.start #A1 polygon {
transform: translate(0px, 0px);
}
</style>
</defs>
<title>Logo</title>
<g id="A1">
<polygon class="right" points="0.33 31.97 0.81 26.09 13.61 3.84 13.13 9.72 0.33 31.97" />
</g>
</svg>
I also noted that jQuery doesn't cause a reflow. Here is an example of inline jquery code that still doesn't fire ready
function before CSSOM is loaded. Instead of inline jquery if we had external jquery then ready event would fire after CSSOM is ready. The understanding I have reached is that CSSOM needs a few milliseconds after html dom is rendered. So till it downloads external jquery CSSOM is ready. DOMContentLoaded
simply don't care if stylesheets are loaded or not, that is it doesn't care if CSSOM is ready or not.
Because that's what DOMContentLoaded does : it fires when the DOM has been parsed, but before the CSSOM has been (and thus before styles have been applied).
If you don't want to wait for the load
event,
one way is to force the browser to paint before your script execution (synchronously), by calling offsetXXX
property on any document's element (e.g <body>
) :
! function() {
window.addEventListener('DOMContentLoaded', function(){
document.body.offsetTop; // force a CSS repaint
var logo2 = document.querySelector("svg");
logo2.classList.add('start');
});
}();
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 104.75 32.46">
<defs>
<style>
polygon {
fill: red;
transition: opacity 3s ease-out, transform 3s ease-out;
opacity: 0;
}
.start polygon {
opacity: 1;
}
#A1 polygon {
transform: translate(100px, 100px);
transition-delay: 1s;
}
/*styles after animation starts*/
.start #A1 polygon {
transform: translate(0px, 0px);
}
</style>
</defs>
<title>Logo</title>
<g id="A1">
<polygon class="right" points="0.33 31.97 0.81 26.09 13.61 3.84 13.13 9.72 0.33 31.97" />
</g>
</svg>
As you can see in second example I added a delay of 0 second but it caused the animations to work, why?
Since the CSS object model have not been loaded when the DOMContentLoaded
event fires
The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading. A very different event load should be used only to detect a fully-loaded page. It is an incredibly popular mistake to use load where DOMContentLoaded would be much more appropriate, so be cautious.
https://developer.mozilla.org/en/docs/Web/Events/DOMContentLoaded
So, adding the css class will not run the animation.
The setTimeOut
method is a javascript event, once fired (even with 0 time), it will be added to the end of the current browser execution queue (which in your case will be added after loading the CSS model). Hence the animation will fire properly.
Update:
But jquery domready fires after CSSOM is loaded. So are all these posts on SO are technically incorrect?
domready
uses DOMContentLoaded
so theoratically speaking, they behave the same way.
Are deferred script tags(both inline or external) executed before CSSOM is loaded?
The script deferred by the defer attribute is executed before the DOMContentLoaded
is fired. So the answer is YES.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With