触发 DOMContentLoaded 后是否应用样式?

Eri*_*AND 5 html javascript css

考虑以下 HTML 文档:

<!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>
Run Code Online (Sandbox Code Playgroud)

div 的不透明度应该设置为 0,并且不透明度的过渡时间为 5 秒。

当 DOM 加载时,主体会被赋予一个将 div 不透明度设置为 1 的类。

我预计 div 不透明度会在 5 秒内从 0 转变为 1。但由于某种原因,它立即发生。

如果我使用 setTimemout,每个都会按预期工作:

<!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>
Run Code Online (Sandbox Code Playgroud)

让我想知道样式是在触发 DOMContentLoaded 事件后加载的。这是正常行为还是我在这里做错了什么?

Nic*_*lay 5

简洁版本:

您正在进入未明确行为的领域。我建议您使用该load事件来触发转换。

长版:

当元素的 CSS 属性的计算值更改 ( spec ) 时,会触发 CSS 转换,因此在样式系统首先计算文档的样式之前无法触发 CSS 转换。

样式系统应该在加载相关样式表后对文档执行初始样式传递(即第一次计算计算值)——否则它将必须在样式表完成加载后重新执行工作。

另一方面,它的想法DOMContentLoaded是在解析 HTML 源代码后立即触发——无需等待任何其他资源(包括样式表)完成加载,因此它自然可以在计算任何样式之前触发

浏览器具有复杂的启发式方法,可以阻止内联脚本的执行(从而阻止解析和 DOMContentLoaded)并确定初始布局和绘制何时发生。脚本可以强制 reflow/restyle,因此根据特定的网页代码和时间,样式信息可能在脚本运行时可用。我不确定它是否在所有浏览器中都能可靠地工作,但强制布局DOMContentLoaded可能会导致您的转换正常工作:

div.offsetTop // force layout
Run Code Online (Sandbox Code Playgroud)

  • 我确认通过使用 window.load 事件,它可以完美地工作。 (2认同)

mar*_*ice 5

来自Mozilla 文档:

当初始 HTML 文档完全加载和解析后,将触发DOMContentLoaded事件,无需等待样式表、图像和子框架完成加载。

该文档建议您应该使用 load 事件:

一个非常不同的事件加载应该仅用于检测完全加载的页面。

所以你会这样做:

window.addEventListener('load', function() {
        document.getElementById('body').className += "loaded";
});
Run Code Online (Sandbox Code Playgroud)

请注意,我不仅更改了事件名称,还更改了分配侦听器的对象。