第 199 题:CSS 会阻塞 DOM 解析吗?

发布于 2022-11-19 14:23:24 字数 56 浏览 119 评论 7

W3C 文档对象模型(DOM)是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

饮惑 2022-05-04 12:46:49

为什么 link css 放在body 中间,会造成 DOM 解析阻塞和渲染阻塞?chrome 92

可以参考这个,页面加载时会被 JS 和 CSS 阻塞吗?

css 阻止渲染是为了防止样式闪烁,这点三大浏览器都一样,只不过对比 link in body 情况 chrome、edge 选择组织解析 DOM,不组织渲染,这样同样会有可能样式闪烁,好处就是,渐进式渲染页面内容给用户看,这就属于特殊行为了。最好还是统一路径放在 head。

顾铮苏瑾 2022-05-04 12:37:55

为什么 link css 放在body 中间,会造成 DOM 解析阻塞和渲染阻塞?chrome 92

可以参考这个,页面加载时会被 JS 和 CSS 阻塞吗?

§普罗旺斯的薰衣草 2022-05-03 20:42:30

大佬你可能要改了,刚刚测试了下,CSS 会阻塞 DOM 解析,当 link-in-body

感性 2022-05-03 17:48:17

为什么 link css 放在body 中间,会造成 DOM 解析阻塞和渲染阻塞?chrome 92

晨曦慕雪 2022-05-03 08:06:28

浏览器的渲染

浏览器的渲染流程如下:

图:WebKit 主流程

图:WebKit 主流程

图:Mozilla 的 Gecko 呈现引擎主流程(3.6)

图:Mozilla 的 Gecko 呈现引擎主流程(3.6)

结合上图,一个完整的渲染流程如下:

  • 渲染进程解析 HTML 内容转换为能够读懂的 DOM 树结构,解析 CSS 为 CSSDOM
  • 把 DOM 和 CSSOM 结合起来生成渲染树(Render Tree)
  • 渲染树构建好了之后,将会执行布局过程,它将确定每个节点在屏幕上的确切坐标
  • 把渲染树展示到屏幕上。再下一步就是绘制,即遍历渲染树,并使用UI后端层绘制每个节点。

值得注意的是:

关键的点在于上述的 4 步并不是以严格顺序执行的。渲染引擎会以最快的速度展示内容,也就是说,浏览器一边解析 HTML,一边构建渲染树,构建一部分,就会把当前已有的元素渲染出来。如果这个时候外部样式并没有加载完成,渲染出来的就是浏览器默认样式了。

其它阶段也是如此。由于浏览器会尝试尽快展示内容,所以内容有时会在样式还没有加载的时候展示出来。这就是经常发生的FOCU(flash of unstyled content)或白屏问题。

CSS 加载不会阻塞 DOM 树的解析

由浏览器的渲染流程图可知,DOM 解析和 CSS 解析是两个并行的进程,所以 CSS 加载不会阻塞 DOM 树的解析

CSS 加载会阻塞 DOM 树的渲染

Render Tree是依赖于 DOM Tree 和 CSSOM Tree 的,所以无论 DOM Tree 是否已经完成,它都必须等待到 CSSOM Tree 构建完成,即 CSS 加载完成(或 CSS 加载失败)后,才能开始渲染。

因此,CSS加载是会阻塞 DOM 树的渲染

<head>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            var p = document.querySelector('p')
            console.log(p)
        })
    </script>
    <link rel="stylesheet" href="./static/style.css?sleep=3000">
</head>

<body>
    <p>hello world</p>
</body>

案例来源:关于 JS 与 CSS 是否阻塞 DOM 的渲染和解析

CSS 的加载并没有阻塞 DOM 树的解析,p 标签是正常解析的,但 p 标签加载完后,页面是迟迟没有渲染的,是因为 CSS 还没有请求完成,在 CSS 请求完成后,hello world 才被渲染出来,所以 CSS 会阻塞页面渲染

DOMContentLoaded:只有当纯 HTML 被完全加载以及解析时,DOMContentLoaded 事件会被触发,它不会等待样式表,图片或者子框架完成加载

CSS 加载会阻塞其后的 JS 执行

由浏览器的渲染流程图可知,JS 的加载、解析与执行会阻塞 DOM 的构建,也就是说,在构建 DOM 时,HTML 解析器若遇到了 JS,那么它会暂停构建 DOM ,将控制权移交给JS引擎,等 JS 引擎运行完毕,浏览器再从中断的地方恢复 DOM 构建。

这也是建议将 script 标签放在 body 标签底部的原因。

由浏览器的渲染流程图可知,DOM 和 CSSOM 的构建是互不影响,但如果在 JS 脚本前引入外部 CSS 文件喃?

<html>
    <head>    
        <link href="theme.css" rel="stylesheet">
    </head>
    <body>    
        <div>hello world</div>    
        <script>        
            console.log('hello world')    
        </script>    
        <div>hello world</div>
    </body>
</html>

它的执行流程:

此时 CSS 也阻塞 DOM 的生成

这是因为 JS 不只是可以改 DOM ,它还可以更改样式,也就是它可以更改 CSSOM 。而不完整的 CSSOM 是无法使用的, JS 中想访问 CSSOM 并更改它,那么在执行 JS 时,必须要能拿到完整的CSSOM。

所以就导致了一个现象,如果浏览器尚未完成 CSSOM 的下载和构建,而我们却想在此时运行脚本,那么浏览器将延迟脚本执行和 DOM 构建,直至其完成 CSSOM 的下载和构建。也就是说,在这种情况下,浏览器会先下载和构建 CSSOM ,然后再执行JS脚本,最后在继续构建 DOM 。

如果也有 JS 加载喃?

<head>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            var p = document.querySelector('p')
            console.log(p)
        })
    </script>
    <link rel="stylesheet" href="./static/style.css?sleep=3000">
    <script src="./static/index.js"></script>
</head>

<body>
    <p>hello world</p>
</body>

HTML 文件中包含了 CSS 的外部引用和 JS 外部文件,HTML 同时发起这两个文件的下载请求,不管 CSS 文件和 JS 文件谁先到达,都要先等到 CSS 文件下载完成并生成 CSSOM,然后再执行 JavaScript 脚本,最后再继续构建 DOM,构建布局树,绘制页面。

所以一般将 <script> 放在 <link> 标签前面

如何优化渲染流程

即如何减少白屏时间?

  • 使用内联 JS、CSS ,减少 JS 、 CSS 文件的下载
  • webpack 等工具对 JS、CSS 文件压缩,减少文件大小
  • 使用 async 或者 defer
  • 使用 CDN 等

原文

陪我终i 2022-05-02 23:20:55
  • css加载不会阻塞DOM树的解析
  • css加载会阻塞DOM树的渲染
  • css加载会阻塞后面js语句的执行

参考链接

~没有更多了~

关于作者

混吃等死

暂无简介

0 文章
0 评论
626 人气
更多

推荐作者

醉城メ夜风

文章 0 评论 0

远昼

文章 0 评论 0

平生欢

文章 0 评论 0

微凉

文章 0 评论 0

Honwey

文章 0 评论 0

qq_ikhFfg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文