浏览器渲染机制
顿号页面加载过程
首先在总结浏览器渲染过程之前,先简单粗略的梳理下页面的加载过程,以便能更好的去理解这个整体过程。
- 浏览器根据域名访问DNS服务器,得到相应IP地址
- 向解析后的IP地址发送HTTP请求
- 服务器收到、处理并返回相应请求
- 浏览器收到请求的内容
例如在浏览器输入www.xiejunjienet.com 后,然后通过DNS解析出IP地址159.89.155.131;然后浏览器会向该地址服务器进行HTTP请求;
服务器发送请求返回HMTL 格式的字符串,因为只有 HTML 格式浏览器才能正确解析。
浏览器渲染过程
浏览器渲染过程大体分为以下几部分:
解析文件
1.HTML解释器——HTML字符串描述了一个页面的组成结构,浏览器回想HTML结构解析成DOM树结构。
2.CSS解释器——解析CSS文件,形成CSS规则树,和DOM树的结构比较像。
3.JavaScript引擎——JavaScript脚本文件加载后,通过DOM API和 CSSOM API来操作DOM树和CSS规则树。
渲染树生成
文件解析完成后,浏览器引擎会通过解析后的DOM树和CSS规则树进行结合,并生成渲染树。
- 渲染树只包含需要展示的节点和其样式详情;
- CSS的规则树会匹配并附加到渲染树的每个相应节点;
- 然后计算每个节点的位置,即layout和reflow过程;
绘制图层,得到页面
浏览器会根据DOM,把页面的图层转化为像素,并对所有资源文件进行解码,最后浏览器会合并各个图层,将数据由CPU输出给GPU最终绘制在屏幕上。
细节拓展补充:
Load 和 DOMContentLoaded 区别
Load 事件触发代表页面中的 DOM,CSS,JS,图片已经全部加载完毕。
DOMContentLoaded 事件触发代表初始的 HTML 被完全加载和解析,不需要等待 CSS,JS,图片加载。
阻塞问题
-
当 HTML 解析到 script 标签时(特殊情况如:async、defer),会暂停构建 DOM,完成后再会从暂停的地方继续开始构建。并且 CSS 也会影响 JS 的执行,只有当解析完样式表才会执行 JS,所以也可以认为这种情况下,CSS 也会暂停构建 DOM。
- <script src="script.js"></script>
没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。 - <script async src="script.js"></script>
有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。 - <script defer src="myscript.js"></script>
有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。
- <script src="script.js"></script>
-
在构建 CSSOM 树时,会阻塞渲染的进度,直至 CSSOM 树构建完成。构建 CSSOM 树是个很消耗性能的过程,所以应该尽量保证节点层级扁平化和减少过度层叠。
图层
一般来说,可以把普通文档流看成一个图层。特定的属性可以生成一个新的图层。不同图层的渲染互不影响,所以说对于某些频繁需要渲染的情况下可以建议单独生成一个新图层,提高性能。但也不能生成过多的图层,可能会适得其反。注:尽量将一个动画元素单独设置为一个图层(避免重绘或者回流的大小)
通过以下几个常用属性可以生成新图层:
- 3D 变换:translate3d、translateZ
- will-change (https://developer.mozilla.org/zh-CN/docs/Web/CSS/will-change)
- video、iframe标签
- 通过动画实现的opacity动画转换
- position:fixed
关于回流和重绘
回流:
常见的引起回流的属性和方法
- 添加或者删除可见的DOM元素;
- 元素尺寸改变——margin、border、padding、width、height;
- 页面的内容变化,比如用户在input框中输入文字;
- 浏览器窗口尺寸改变——即resize事件发生时;
- 计算 offsetWidth 和 offsetHeight 属性;
- 设置 style 属性的值;
重绘:
是当节点需要更改外观而且不会影响布局的情况下称为重绘。
常见的引起重绘的属性和方法
- color、background、box-shadow、visibility、border-radius、outline等;
如何减少回流、重绘
- 使用 translate 替代 top;
- 使用visibility替换display:none,因为前者只会引起重绘,后者会引发回流(改变了布局);
-
不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局;
- CSS 选择符从右往左匹配查找,避免 DOM 深度太深;
-
动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用requestAnimationFrame;
- 将频繁运行的动画变为图层,图层能够阻止该节点回流影响别的元素。比如对于video标签,浏览器会自动将该节点变为图层。