Reputation: 6786
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 ?
Upvotes: 5
Views: 5489
Reputation: 31
Today is the 16th of september in 2024. The FOUC bug is active in Firefox 130.0. I get the FOUC-Bug on larger sites, not with my customer websites. Because of a restrictive Content-Security-Policy it is not possible to use tricks with script content within the page. I use the "hidden" attribute and the load Event as follows:
<nav hidden class="navbar navbar-expand-lg fixed-top" >
window.addEventListener("load", () => {
const navs = document.getElementsByTagName("NAV")
const nl = (navs) ? navs.length : 0
for(let idx = 0; idx < nl; idx++)
{
navs[idx].removeAttribute("hidden")
}
});
Upvotes: 0
Reputation: 1042
From the Mozilla Documentation:
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.
The documentation suggests that you should instead use the load event:
A very different event load should be used only to detect a fully-loaded page.
So you would do it like this:
window.addEventListener('load', function() {
document.getElementById('body').className += "loaded";
});
Note that I didn't only change the event name but also changed the object that I assign the listener to.
Upvotes: 6
Reputation: 32073
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
Upvotes: 5