Consider the following HTML document:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
body {
background: crimson;
}
div {
transition: opacity 5s;
font-size: 4em;
opacity: 0;
}
.loaded div {
opacity: 1;
}
</style>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('body').className += "loaded";
})
</script>
</head>
<body id="body">
<div>
TEST
</div>
</body>
</html>
The div is supposed to have its opacity set to 0 and a 5s transition on opacity.
When the DOM is loaded, the body is given a class that set the div opacity to 1.
I'm expecting the div opacity to transition from 0 to 1 in 5s. But for some reason, it happens immediately.
If I use setTimemout, every works as expected:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
body {
background: crimson;
}
div {
transition: opacity 5s;
font-size: 4em;
opacity: 0;
}
.loaded div {
opacity: 1;
}
</style>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
document.getElementById('body').className += "loaded";
}, 0);
})
</script>
</head>
<body id="body">
<div>
TEST
</div>
</body>
</html>
Makes me wonder is styles are loaded after DOMContentLoaded event is triggered. Is this a normal behavior or am I doing something wrong here ?
Short version:
You're getting into the area of underspecified behavior. I suggest you use the load
event for triggering the transition.
Long version:
A CSS transition is triggered when computed values of an element's CSS properties change (spec), so it can not be triggered before the style system first computes the styles for the document.
The style system ought to do the initial styling pass on the document (i.e. calculate the computed values the first time) after it loads the relevant stylesheets -- otherwise it will have to re-do the work after the stylesheets finish loading.
On the other hand, the idea of DOMContentLoaded
is to fire as soon as the HTML source is parsed -- without waiting for any other resources (including stylesheets) to finish loading, so it naturally can fire before any style was calculated.
The browsers have complicated heuristics that block execution of inline scripts (and thus parsing and DOMContentLoaded) and determine when the initial layout and painting happens. The scripts can force reflow/restyle, so depending on the specific web page code and timing, the styling information may be available by the time your script runs. I'm not sure if it works reliably in all browsers, but forcing layout from DOMContentLoaded
might cause your transition to work:
div.offsetTop // force layout
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