我正在参加「掘金·启航计划」
前言
浏览器渲染是老生常谈的事,现在可以算是前端工程师的必备技能了,如果你还不知道重排和重绘到底是什么,请抽出一段空余时间认真阅读本篇文章,相信阅读完后会对你有所帮助。
渲染过程
还是拿出这张图,我们来从头梳理一遍:
从上图我们可以得出,与渲染有关的任务:
- DOM:将HTML解析为DOM树,开发者可以在浏览器控制台输入document感知;
- Style:解析CSS,开发者可以在浏览器控制台输入document.styleSheets感知;
- Layout:构建布局树,布局树会移除DOM树中不可见的部分,并计算可见部分的几何位置,生成渲染树;
- Layer:将页面划分为多个图层,一些层叠上下文CSS属性(如z-index、opacity、position)、“由于显示不全被裁减的内容”等会使DOM元素形成独立的图层;
- Paint:为每个图层生成包含“绘制信息”的绘制列表,将绘制列表提交给渲染进程的合成进程用于绘制;
- 合成:合成线程为Paint阶段绘制出来的图层进行合成,类似于Photoshop中的图层。
上述最后两点(Paint、合成)继续细分为:
- 对渲染树进行分层操作,并生成分层树;
- 为每个图层生成绘制列表,并提交到合成线程;
- 合成线程将图层分成不同的图块,并通过栅格化将图块转化为位图;
- 合成线程给浏览器进程发送绘制图块指令;
- 浏览器进程会生成页面,并显示在屏幕上。
最后,绘制的最终产物是一张图片,这张图片被发送给显卡后即可显示在屏幕上。我们所看到的的动画实际上其实也就是一张张的图片,屏幕以我们肉眼看不见的频率(一般是60Hz,即每秒刷新60次)在刷新
渲染流水线
执行上述任务的流程被称为“渲染流水线”。每次执行流水线时,上述任务不一定全部都执行,比如:
- 当通过JS或CSS修改DOM元素的几何属性(比如长度、宽度)时,会触发完整的渲染流水线,这种情况称为重排。
- 当修改的属性不涉及几何属性(比如字体颜色、背景颜色)时,会省略渲染流水线中的Layout、Layer过程,这种情况称为重绘。
- 当修改不涉及重排、重绘的属性(比如transform属性)时,会省略渲染流水线中的Layout、Layer、Paint过程,仅执行合成线程的绘制工作,这种情况称为合成。
根据上述所例,我们可以知道,按照性能高低对这些流程进行排序的话:重排<重绘<合成
这也是为什么CSS动画优于JS动画性能的原因,CSS动画可能仅涉及合成,而JS动画会涉及重排、重绘。
知识补充
拥有层叠上下文属性的元素
我们看到的页面通常是二维的平面,而层叠上下文能够让页面具有三维的概念。这些 HTML 元素按照自身属性的优先级(从下到上)分布在垂直于二维平面的 z 轴上。
- 背景和边框:建立当前层叠上下文元素的背景和边框。
- 负的z-index:当前层叠上下文中,z-index属性值为负的元素。
- 块级盒:文档流内非行内级非定位后代元素。
- 浮动盒:非定位浮动元素。
- 行内盒:文档流内行内级非定位后代元素。
- z-index:0:层叠级数为0的定位元素。
- 正z-index:z-index属性值为正的定位元素。
需要裁剪的元素
什么是裁剪呢?
假如有一个固定宽高的div盒子,而里面的文字较多超过了盒子的高度,这时就会产生裁剪。
浏览器渲染引擎会把裁剪文字内容的一部分用于显示在 div 区域。当出现裁剪时,浏览器的渲染引擎就会为文字部分单独创建一个图层,如果出现滚动条,那么滚动条也会被提升为单独的图层。