Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are styles applied after DOMContentLoaded is triggered?

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 ?

like image 947
Eric MORAND Avatar asked Jan 30 '23 08:01

Eric MORAND


1 Answers

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
like image 157
Nickolay Avatar answered Jan 31 '23 22:01

Nickolay