探秘浏览器页面渲染过程:从代码到视觉的奇妙之旅
当我们在地址栏输入网址并按下回车键后,浏览器是如何将 HTML、CSS 和 JavaScript 代码转化为我们眼前看到的页面呢?这背后隐藏着一个复杂而精妙的过程 —— 浏览器页面渲染。
一、DOM 树的构建
浏览器接收 HTML 代码后,首先要做的就是将这些结构字符串解析转换为 DOM 树形结构。DOM 树构建完毕时,会触发DOMContentLoaded事件,这意味着页面的基本结构已经搭建完成,后续的 JavaScript 代码可以开始对页面元素进行操作。
DOM 树的构建并非一蹴而就,它包含多个步骤:
- 浏览器先把 HTML 原始字节通过 UTF-8 编码解析为字符串。
- 将解析的字符串进一步拆解为 Token,Token 是 HTML 语法的最小单位,像
<div>、<p>这样的标签,或者class="example"这样的属性,甚至是标签中的文本内容,都属于 Token。 - 浏览器根据 Token 生成节点对象,并将它们有序地组合成 DOM 树,每个节点都代表着页面中的一个元素,节点之间的层级关系构建出了页面的结构脉络。
以一个简单的 HTML 代码片段为例:
<!DOCTYPE html>
<html lang="en">
<head>
<title>文档标题</title>
</head>
<body>
<a>我的链接</a>
<h1>我的标题</h1>
</body>
</html>
其对应的 DOM 树结构大致如下:
二、CSS 解析与 CSSOM 树构建
在 HTML 解析的同时,浏览器也在并行处理 CSS 代码,但这两者之间存在着阻塞关系。如果 CSS 代码中包含复杂的样式规则,解析过程可能会影响 HTML 的解析速度。
CSSOM 树的构建过程与 DOM 树类似:
- 浏览器先把 CSS原始字节通过 UTF-8 编码解析为字符串。
- 将字符串解析为Token,
Token在这里表现为 CSS 语法中的最小单位,如body { background-color: white; }中的body选择器、background-color属性以及white值等。 - 根据 Token 生成节点对象,并将它们有序地组合成 CSSOM 树。
假设有如下 CSS 代码:
body {
font-family: Arial, sans-serif;
background-color: lightblue;
}
h1 {
color: red;
}
a {
color: green;
}
对应的 CSSOM 树结构简化表示如下:
CSSOM
--body
--font-family: Arial, sans-serif
--background-color: lightblue
--h1
--color: red
--p
--color: green
三、渲染树构建:结构与样式的融合
当 DOM 树和 CSSOM 树生成完毕后,浏览器便开始将这两棵树组合为渲染树。
- 渲染树并非简单地将 DOM 和 CSSOM 合并,而是一个应用规则和计算的过程。
- 它只包含页面中可见的元素,像设置了
display: none的元素不会出现在渲染树中。 - 渲染树的每个节点都包含了元素的几何信息,如位置、大小,以及颜色、字体等样式属性,这些信息决定了元素在页面中的最终呈现效果。
结合前面的 DOM 树和 CSSOM 树示例,生成的渲染树会包含h1和a元素,并且它们带有从 CSSOM 树中获取的样式信息,例如h1元素的颜色为红色,a元素的颜色为绿色等。渲染树节点结构简化示意如下:
Render Tree
--h1 (color: red)
--"Welcome to my page"
--a (color: green)
--"This is a paragraph."
四、布局和绘制:从数据到视觉的呈现
-
布局与绘制的概念
渲染树构建完成后,浏览器进入布局与绘制阶段。
- 布局过程负责根据元素的属性计算每个元素在页面中的精确位置和大小,就好比在图纸上规划每个物体的摆放位置。
- 绘制阶段则是将元素的样式信息转化为屏幕上的像素,就像将设计好的图案绘制在画布上。
-
在页面的使用过程中,如果对元素进行了修改,就可能触发重新布局(回流 reflow)和重新绘制。
-
回流:当
RenderTree(渲染树) 中的部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程。 -
重绘:当渲染树中的一些元素需要更新,而这些属性只是影响元素的外观、风格,而不会影响布局的,比如background-color。则就叫称为重绘。即当页面元素的样式发生改变,但布局没有发生变化时,文档流没有发生变化。
例如:当我们修改元素的
width或height属性时,会触发重新布局和重新绘制;但如果只是修改color属性,通常只需要重绘。
其中,回流的开销较大,因为它需要重新计算所有受影响元素的位置和大小;而重新绘制相对性能尚可,因为它只需要更新元素的外观显示。
注意
当元素设置visibility:hidden时,元素虽然不可见,但是元素的空间是存在的。其布局没有发生改变,仅触发重绘。
当元素设置为display:none时,DOM树构建时候会忽略该元素,元素的空间就不存在了,页面布局发生改变。会触发重绘和回流
-
-
不同图层的页面改动
- 每个图层都是一个独立的渲染上下文,都有自己的渲染树,当一个图层的内容发生改变时,浏览器会重新渲染这个图层,而不会影响到其他图层的内容。
- 对于动画元素和离开文档流的元素,浏览器会将其作为单独的图层进行渲染,这样在修改该元素时,只需要更新这一个图层,大大减少了渲染的工作量,提高了页面的性能。
五、页面加载完成:onload事件的触发
当整个页面,包括所有图像、样式表、脚本等外部资源都加载完成后,浏览器会触发onload事件,并执行绑定在该事件上的函数。这标志着页面的所有资源都已准备就绪,此时页面不仅结构完整,样式和功能也全部生效,用户可以开始与页面进行完整的交互。