影响回流、重绘的 CSS 属性有哪些?
目前,比较常见的浏览器内核(渲染引擎)有:WebKit、Blink 、Gecko、Trident、EdgeHTML,更多请看。
- WebKit 课代表是 Safari 浏览器
- Blink 课代表是 Chrome 浏览器(Blink 起源自 WebKit 的一个分支)
- Gecko 课代表是 Firefox 浏览器
- Trident 课代表是 IE 浏览器。2015 年微软推出的 Edge 浏览器其内核是 EdgeHTML。从良之后于 2020 年推出基于 Chromium 的 Edge 浏览器,使用 Blink 引擎。
以下是两个主流浏览器内核 WebKit、Gecko 合成 DOM 的过程:
两者整体流程基本相似,在术语方面也有所不同,比如 WebKit 中的 Layout 过程,Gecko 称为 Reflow。
提高网页性能的其中一个方式就是,减少回流(reflow)、重绘(repaint),分别对应 Layout 和 Painting 过程。
比如,React Hooks 中处理副作用时,某些场景下应选择 useLayoutEffect
,而不是 useEffect
的原因正是为了减少回流重绘的过程。
「回流」也有称作「重排」的。
什么是卡顿?
在很长一段时间里,显示器的刷新率多数为 60Hz,即使到现在仍然是占多数。
刷新率(RefreshRate),表示单位时间内能够绘制新图像的次数。举个例子,60Hz 的刷新率,表示显示器要在一秒内刷新 60 次图像,换句话说,一次图像的更新要在 16.67ms
内完成。这样才不会造成卡顿。如果超出这个时间,在视角上就会产生卡顿感。
60Hz 的刷新率是人类不会感觉到屏幕图像闪烁的数值,由科学家验证得出。
附一个来自网上的图:
还是用 React 举例吧。我们知道 React 16 起采用了全新的 Fiber 架构,就是为了解决大型应用卡顿的问题。
我们知道,浏览器是多进程的,JavaScript 是单线程的。浏览器会为每个标签(Tab)分配一个进程,每个进程由 GUI 渲染线程、JS 线程、定时器线程、网络线程、事件线程多个线程组成。最重要的一点是:GUI 渲染线程与 JS 线程是互斥的。换句话说,某个时刻它只能执行其中一个线程,等待该线程执行完毕之后,才将执行权交由另一个线程。
那么为什么 React 15 在处理大型应用的时候会卡顿呢?
首先 React 15 架构,由协调器(Reconciler)和渲染器(Render)组成。而 React 16 在原来的基础上新增了调度器(Scheduler),用于调度任务的优先级。
在 React 15 的 Reconciler 中,组件的挂载(Mounting)、更新(Updating)会对应调用 mountComponent
、updateComponent
方法,它们内部会执行递归操作,以更新子组件。**但是递归执行的缺点是「无法中断」。**假设 JS 线程执行递归耗时超过了 16.67ms
,由于互斥期间 GUI 线程并不能执行任何的操作,等递归完并生成新的虚拟 DOM 之后,触发 DOM 等更新,此时由 GUI 线程进行处理,可能包括回流、重绘的过程,然后才完成一次页面的更新。由于无法满足刷新率的要求,就会产生卡顿感。
因此,解决卡顿的思路就是:在每一帧的时间内,预留一些时间给 JS 线程,当预留的时间不够用时,React 中断当前任务,将线程控制权交换给浏览器,使其有时间渲染页面,等下一帧到来的时候,继续被中断的工作。
在 React 16 新增的 Scheduler 可以使得浏览器有剩余时间的时候通知 React,而且提供了多种调度优先级,使得更高优先级的任务优先进入 Reconciler 阶段。 而 Reconciler 则是利用了 Fiber 这种架构实现了**「可中断的异步更新」**(请注意,这里的异步并不是由 setTimeout
实现的,由于精度问题,setTimeout
实际上最低延迟时间是 4ms
,在这寸土寸金的一帧时间才 16.67ms
,显然是不合理的)。
因此,React 就是采用了这种思路来解决大型应用卡顿问题的。
题外话扯完了,回到本文的主题...
影响页面渲染性能的有什么?
再附上一张源自网上的图:
这几个关键点:
- JavaScript - 使用 JavaScript 脚本来触发 DOM 的更新。
- Style - 匹配各种选择器,并计算出哪些元素应用哪些 CSS 样式的过程。
- Layout - 前面知道一个元素应用哪些规则之后,浏览器开始计算它要占用的空间大小以及在屏幕的位置。一个元素在空间上的变化,会同时影响其他元素的重排。
- Paint - 绘制是填充的像素的过程,比如文本、颜色、图像、边框和阴影等。
- Composite - 合成过程处理元素绘制到哪一层,可能是在某个元素的上层或下层。与层叠上下文有关。
- 如果修改了某个元素的 Layout 属性,那么浏览器会检查其他所有元素,然后“自动重排”,任何受影响的部分都需要重新绘制,然后才进行合成。
- 如果仅修改了「paint only」属性,比如背景图片,文字颜色、背景等,它不会影响页面布局,所以会跳过 Layout 阶段,然后执行重绘。
- 如果修改了一个既不影响 Layout,也无需 Paint 的属性,那么浏览器只执行 Composite 合成过程。这个开销是最小的,可以看下这篇文章。
CSS Triggers
哪些 CSS 属性影响 Layout,哪些影响 Paint 呢?
可以看这个网站 CSS Triggers。
其中 Change from default 表示从未设置(即 CSS 默认值)到设置为其他值,Subsequent updates 表示属性修改。
References
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论