# 前言
上一章梳理了浏览器三大核心内容:渲染引擎、渲染过程、兼容性。其中渲染过程里的回流和重绘是CSS中很重要的概念。了解和认识它们,可编写出性能更好的CSS代码。
有些同学说,怎么不开发完CSS再找时间优化呢?试问有多少同学开发完一个项目后会拿出空余时间重构或优化你的代码。何必不在编码时对CSS代码进行一次完美的编写呢?接下来隆重介绍本章的两位主角。
# 回流
回流又名重排,指几何属性需改变的渲染。但是感觉回流这个词比较高大上,后续统称回流吧。
可理解成,将整个网页填白,对内容重新渲染一次。只不过以人眼的感官速度去看浏览器回流是不会有任何变化的,若你拥有闪电侠的感官速度去看浏览器回流(实质是将时间调慢),就会发现每次回流都会将页面清空,再从左上角第一个像素点从左到右从上到下这样一点一点渲染,直至右下角最后一个像素点。每次回流都会呈现该过程,只是感受不到而已。
渲染树的节点发生改变,影响了该节点的几何属性,导致该节点位置发生变化,此时就会触发浏览器回流并重新生成渲染树。回流意味着节点的几何属性改变,需重新计算并生成渲染树,导致渲染树的全部或部分发生变化。
# 重绘
重绘指更改外观属性而不影响几何属性的渲染。相比回流,重绘在两者中会温和一些,后续谈到的CSS性能优化就会基于该特点展开。
渲染树的节点发生改变,但是不影响该节点的几何属性。由此可见,回流对浏览器性能的消耗是高于重绘的,而且回流一定会伴随重绘,重绘却不一定伴随回流。
为何回流一定会伴随重绘呢?整个节点的位置都变了,肯定要重新渲染它的外观属性啊!
# 属性分类
以下对一些常用的几何属性和外观属性分类,其实同种分类的属性都有一些共同点,各位同学可自行感受。推荐一个查询CSS属性渲染状态的网站CssTriggers,可查看每个属性在渲染过程中发生了什么影响了什么
- 几何属性:包括布局、尺寸等可用数学几何衡量的属性
- 布局:display、float、position、list、table、flex、columns、grid
- 布局:display、float、position、list、table、flex、columns、grid
- 外观属性:包括界面、文字等可用状态向量描述的属性
- 界面:appearance、outline、background、mask、box-shadow、box-reflect、filter、opacity、clip
- 文字:text、font、word
如何理解回流重绘
有无更好的方法可帮助理解回流重绘呢?答案是有的。
某一天星巴克发行一套很有纪念价值的杯子,男同胞们为了买到心仪的杯子给女友当惊喜礼物,通宵达旦搬张板凳去星巴克门口排队。此时形成的队伍是有序的,毕竟大家都是文明人,不可能随便插队吧,先到先拿,这个道理谁都懂!
可是总有一些人不按常理出牌,别人排队排得那么辛苦,他一到来就仗着自己有钱有势人多马多,插队到最前面。若他插队成功,那么后面的人都要往后挪一位。此时队伍就要重新往后挪,甚至引发多人斗殴。但是混乱的情况总会被控制下来,此时就得重新排队,而原先的队伍顺序经过这次斗殴就可能不按照原先的队伍顺序排队了。几何属性变了,就要重新排队,这个就是回流或重排。重新排队啊😂!
一位漂亮妹纸排队排得久肚子呱呱叫,就与另一位同伴交换,她去买早餐,而这位同伴代替她的位置。各位男同胞可能发现这位妹纸更漂亮了。没错,外观属性改变了,变漂亮了,但是除了妹纸,其余人的位置和顺序都无发生变化,所以肯定不会发生上述重新排队的情况。外观属性变了,但是几何属性没变,这个就是重绘。不用重新排队,还有漂亮妹纸看,大家都很乐意🤔!
# 性能优化
回流重绘在操作节点样式时频繁出现,同时也存在很大程度上的性能问题。回流成本比重绘成本高得多,一个节点的回流很有可能导致子节点、兄弟节点或祖先节点的回流。在一些高性能电脑上也许无什么影响,但是回流发生在手机上(明摆说某些安卓手机),就会减缓加载速度和增加电量消耗。
在上一章中引出一个定向法则:回流必定引发重绘,重绘不一定引发回流,可利用该法则解决一些因为回流重绘而引发的性能问题。在优化性能前,需了解什么情况可能产生性能问题,以下罗列一些常见的情况。
- 改变窗口大小
- 修改盒模型
- 增删样式
- 重构布局
- 重设尺寸
- 改变字体
- 改动文字
很多同学可能不知,回流重绘其实与浏览器的事件循环有关,以下源自对HTML文档的理解
- 浏览器刷新频率为
60Hz,即每16.6ms更新一次 - 事件循环执行完成微任务
- 判断
document是否需更新 - 判断
resize/scroll事件是否存在,存在则触发事件 - 判断
Media Query是否触发 - 更新动作并发送事件
- 判断
document.isFullScreen是否为true(全屏) - 执行
requestAnimationFrame回调 - 执行
IntersectionObserver回调 - 更新界面
上述就是浏览器每一帧中可能会做到的事情,若在一帧中有空闲时间,就会执行
requestIdleCallback回调。
回到正题,通过定向法则回流必定引发重绘,重绘不一定引发回流可知道,尽量减少回流重绘,就是CSS性能优化中一个很好的指标。
如何减少和避免回流重绘
1. 使用transform代替top
top是几何属性,操作top会改变节点位置从而引发回流,使用
transform:translate3d(x,0,0)代替top,只会引发图层重绘,还会间接启动GPU加速,该情况在第12章变换与动画中会详细讲解。
2. 使用visibility:hidden替换display:none
笔者从以下四方面对比
display:none和visibility:hidden,display:none简称DN,visibility:hidden简称VH
- 占位表现
- DN不占据空间
- VH占据空间
- 触发影响
- DN触发回流重绘
- VH触发重绘
- 过渡影响
- DN影响过渡不影响动画
- VH不
