性能优化——把重排、重绘、合成掰开了、揉碎了学
引言
在前端开发中,有重排(reflow)、重绘(repaint)和合成(compositing)这三个在代码中无处不在,却鲜有人提起的概念,其实这是一名前端进阶道路上绕不开的一道题。
这三个概念,仿佛是渲染引擎的交织舞台,影响着页面的构建、外观和性能。它们如同隐藏在幕布背后的舞者,相互合作,决定了用户的视觉和交互体验。在掌握了它们的本质后,我们将能够优化页面、提升性能,创造出更为流畅和令人惊艳的用户界面。
在接下来的内容中,我们将深入探讨重排、重绘和合成的原理,领略它们在前端开发中的不可或缺性,以及一些优化技巧和最佳实践。
重排(Reflow)
什么是重排、何时重排
重排是指当页面的布局和几何属性发生变化时,浏览器需要重新计算元素的位置和大小。这个过程涉及到整个文档树的重新布局,因此是非常耗费性能的操作。一些可能引起重排的操作包括改变元素的尺寸、位置、内容等。频繁的重排会导致页面的卡顿和响应时间延长。
常见导致重排的操作和行为
- 添加/删除可见的DOM元素
- 修改元素位置属性,如left、top、right等
- 页面初始加载时,以及响应式布局变化时
- 改变页面布局,如宽高、内外边距、浮动等
- 改变字体
- 滚动页面
那么我们可以怎么确认是否触发重排呢?
先来一个demo
在浏览器打开html文件,打开chrome devtools 的permance,开始录制,然后点击按钮 - 缩放窗口,再停止录制。会看到这样的界面,可以选择时间范围以更细致分析:
看到layout就说明浏览器进行重排了,变换时间范围,会发现layout时间不一样,这就是缩放过程中布局不断更新,所以不断触发重排。
优化技巧
-
避免频繁访问布局属性,尽量一次性获取或修改
-
使用 CSS3 动画替代 JavaScript 动画,因为前者通常能利用合成来避免重排
-
将频繁变动的元素设置为绝对定位或固定定位,脱离文档流,以减少对其他元素布局的影响
-
使用虚拟DOM,减少实际DOM操作
重绘(Repaint)
什么是重绘,何时重绘
重绘是指当元素的外观属性(如颜色、背景等)发生变化时,浏览器会重新绘制这些元素。与重排不同,重绘不会改变元素的布局,只是改变元素的外观。尽管重绘的代价相对较小,但仍然需要消耗一定的性能。
常见导致重排的操作和行为
- 改变颜色、背景、阴影等视觉样式
- 设置文本内容或字体样式
- 单独使用transform、opacity来实现动画效果
你可以修改上面的demo来验证,permance里的paint就是重绘。
优化技巧
- 合并多次样式改变,避免重复重绘
- 使用CSS3的transform和opacity属性,它们能够在不引起重排的情况下改变元素外观
- 对动画使用will-change提高合成层创建效率
合成(Compositing)
什么是合成,何时合成
合成是将多个图层合成为最终的屏幕显示。现代浏览器利用硬件加速来进行合成,即利用计算机的GPU来加速图层的合成过程。合成的优化可以显著提高页面的渲染性能,并且减少对CPU的压力。
启用合成层的一些方法
-
使用硬件加速,将部分图层委托给 GPU 处理,加快图层合成速度
-
利用图层的概念,将独立于布局的元素分层,使得只有特定图层的变化会触发合成,而不会引发重排和重绘
-
使用
will-change
属性明确声明哪些属性将会发生变化,帮助浏览器进行优化 -
对3D transform进行动画
-
对元素设置opacity小于1
-
对元素设置video、canvas、WebGL等标签
总结来说,能用CSS的地方就别用JS,这是用合成层优化重排、重绘的根本。
总结
在前端开发的世界中,理解重排、重绘和合成的概念是我们优化性能的重要一环。这些平时工作中极少提起的名词,实际上是良好的用户体验的关键所在。
前端er应该不再把性能优化视为一项任务,而要看作是一种创造力的表达。就像艺术家将每一笔划痕都视为构建完美画作的一部分,我们也能通过优化网页的每一帧,创造出更极致的前端体验。