解析HTML,构建DOM树(这里遇到外链,此时会发起请求)
解析CSS,生成CSS规则树
合并DOM树和CSS规则,生成render树
布局render树(Layout/reflow),负责各元素尺寸、位置的计算
绘制render树(paint),绘制页面像素信息
浏览器会将各层的信息发送给GPU,GPU将各层合成(composite),显示在屏幕上
宏观上可以分为如下的步骤:
字节数据 》 字符串 》token 》Node 》DOM
浏览器会从磁盘或者网络中读取HTML的原始字节,并根据文件的指定编码, 将其转化成字符串
讲字符串转换成token,例如 等。Token中会标识出当前的 开始标签 还是结束标签亦或者是文本信息等
根据这开始结束标签,就可以确定子节点和父节点的关系
DOM树构建过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。
生成节点对象构建DOM 树
(一个 DOM
节点并不总是必须是一个 HTML
元素。当浏览器创建 DOM
树时,它也会将注释、属性、文本等内容作为树中的单独节点保存。但为了简单起见,我们只考虑 HTML
元素的 DOM
节点,也就是 DOM
元素。这里是所有 DOM
节点类型的列表。)
(CSSOM 是一组允许 JavaScript 操作 CSS 的 API。它非常类似于 DOM,但是用于 CSS 而不是 HTML。它允许用户动态读取和修改 CSS 样式。)
但前者要依赖后者,因为只有HTML内容具有完整的树形结构关系,而CSS样式表并没有。
在构建了 DOM
之后,浏览器从所有的源头(外部的、嵌入式的、内嵌的、用户代理的等)读取 CSS
。
多数浏览器都自带样式表,这个样式表被称为用户代理样式表,浏览器首先用开发者属性提供的 CSS
覆盖用户代理样式(使用特定性的规则),计算出 DOM
元素的最终 CSS
属性,然后构造一个节点。
在构建CSSOM树时,对于任何一个元素的最终样式,浏览器都会从适用于该节点的最上层节点开始,通过递归的方式不断向下合并更加具体的规则,最终得出完整的结果,这就是向下级联(Cascade)的含义。
注:(CSS匹配HTML元素是一个相当复杂和有性能问题的事情。所以,DOM树要小,CSS尽量用id和class,千万不要过渡层叠下去。)
浏览器要计算每个可见元素的布局,并把它们画在屏幕上
当一个网页被加载时,浏览器首先读取 HTML
文本并从中构建 DOM
树。然后它处理 CSS
,无论是内嵌的、嵌入式的、还是外部的 CSS
,并从中构建 CSSOM
树。
构建完这些树后,它再从中构建 Render-Tree
。一旦构建了 Render-Tree
,浏览器就会开始在屏幕上打印各个元素。
DOM 和 CSSOM 树的构建都发生在主线程上,而且这些树的构建是同时进行的。它们共同构成了用于在屏幕上打印东西的 Render Tree,而 Render Tree 也随着 DOM 树的构建而逐步构建。
DOM 树的生成是增量的,这意味着当浏览器读取 HTML 时,它会将 DOM 元素添加到 DOM 树中。
与 DOM 树不同,CSSOM 树的构建不是递增的,必须以特定的方式进行。
浏览器在读取 CSS 内容时,不能增量地构建 CSSOM 树。原因是,文件最后的 CSS 规则可能会覆盖写在文件顶部的 CSS 规则。
浏览器不会逐步处理外部 CSS 文件,CSSOM 树更新是在样式表中所有 CSS 规则处理完毕后一次性完成的。CSSOM 树更新完成后,再更新渲染树,然后渲染到屏幕上。
CSS 是一种渲染阻塞型资源。一旦浏览器提出获取外部样式表的请求,Render Tree 的构建就会停止。因此,关键渲染路径(CRP)也被卡住了,没有任何东西被渲染到屏幕上, 然而,在后台下载样式表时,DOM 树的构建仍在进行中。
浏览器可以使用 CSSOM 树的旧状态来生成 Render Tree,因为 HTML 正在被解析,以递增的方式在屏幕上呈现事物。但这有一个巨大的缺点。在这种情况下,一旦样式表被下载和解析,CSSOM 被更新,Render Tree 就会被更新并呈现在屏幕上。现在,用旧 CSSOM 生成的 Render Tree 节点将重绘新的样式,这也可能导致 Flash of Unstyled Content (FOUC),这对用户体验非常不利。
在下载样式表的时候执行 JavaScript 是不安全的。
根据 HTML5 规范,浏览器可以下载一个脚本文件,但不会执行它,除非之前所有的样式表都被解析了。当一个样式表阻止脚本的执行时,它被称为脚本阻塞型样式表(script-blocking stylesheet)或脚本阻塞型 CSS(script-blocking CSS)。
还有一个点
<script>
标签时,会触发页面渲染每次碰到<script>
标签时,浏览器都会渲染一次页面。浏览器不知道脚本的内容,因而碰到脚本时,只好先渲染页面,确保脚本能获取到最新的DOM
元素信息,尽管脚本可能不需要这些信息。
CSS
不会阻塞 DOM
的解析,但会阻塞 DOM
渲染。JS
阻塞 DOM
解析,但浏览器会"偷看"DOM
,预先下载相关资源。<script>
且没有defer
或async
属性的 标签时,会触发页面渲染,因而如果前面CSS
资源尚未加载完毕时,浏览器会等待它加载完毕在执行脚本。转载自下面作者:
作者:sea_ljf
链接:https://juejin.cn/post/6844903497599549453
作者:浪里行舟
链接:https://juejin.cn/post/6844903815758479374
作者:Kerb
链接:https://juejin.cn/post/6952878811046215711