1、动画性能基础:理解浏览器渲染管线
大家好,我是你们的老朋友。今天咱们聊聊动画性能的底层逻辑。
说实话,我刚入行那会儿,觉得动画嘛,不就是改改CSS属性、调调transition?后来被一个滚动卡顿的bug折磨了三天,才意识到——不懂渲染管线,你连问题出在哪都不知道。
这一章,咱们把地基打牢。你想想看,盖楼不打地基,后面30层怎么盖?
1.1 浏览器渲染管线:页面是怎么画出来的?
浏览器把HTML/CSS变成像素,要经过五个阶段。我习惯叫它「五步走」:
- JavaScript:执行脚本,触发视觉变化
- Style:计算样式,匹配CSS选择器
- Layout:计算几何信息,确定每个元素的位置和大小
- Paint:绘制像素,填充颜色、边框、阴影
- Composite:合成图层,输出到屏幕
嗯,这里要注意——不是每次更新都会走完五步。具体走几步,取决于你改了什么东西。
核心结论:动画性能优化的本质,就是让浏览器走更少的步骤。
1.2 重排、重绘、合成——三兄弟的区别
这三兄弟,我一个个说清楚。
重排(Reflow)
改了什么?位置、尺寸、显示隐藏。比如改了width、height、margin、display: none。
后果是什么?整个五步全走一遍。代价最大。
我在项目中遇到过,一个表格里动态插入行,结果整个页面都在抖。为什么?因为每一行插入都触发了全局重排。
重绘(Repaint)
改了什么?视觉外观但不影响布局。比如改了color、background-color、visibility。
后果是什么?跳过Layout,走Style → Paint → Composite。代价中等。
合成(Composite)
改了什么?只影响合成的属性。比如transform、opacity。
后果是什么?只走Composite一步。代价最小,60fps的黄金搭档。
我的经验:能用transform就别用left/top。能用opacity就别用display。这是最基础的避坑指南。
1.3 60fps目标与帧预算
为什么是60fps?因为人眼的视觉暂留效应。低于这个数,你就会觉得卡。
60fps意味着什么?每帧只有16.67ms。我算给你看:
1000ms ÷ 60帧 ≈ 16.67ms/帧
这16.67ms里,浏览器要干完所有活——JS执行、样式计算、布局、绘制、合成。留给你的时间,其实只有10ms左右。
我曾经犯过一个错:在一个滚动监听里做了大量DOM操作,结果每帧耗时超过50ms。用户滚动时就像在看幻灯片。后来我用Performance面板一查,重排占了40ms。嗯,从那以后我再也不敢在滚动回调里乱改布局了。
警告:别以为16.67ms很多。实际上,超过10ms你就该警惕了。超过16ms,卡顿是必然的。
1.4 性能分析工具概览
光说不练假把式。工具得会用。我平时最常用的三个:
| 工具 | 用途 | 我的用法 |
|---|---|---|
| Chrome Performance | 录制帧耗时、查看渲染流水线 | 先录一段,看有没有超过16ms的帧 |
| Layers面板 | 查看合成层、检测层爆炸 | 看有没有不必要的图层 |
| Rendering面板 | 实时显示FPS、绘制矩形、层边界 | 打开FPS Meter,边操作边看 |
我个人习惯,先开Rendering面板的FPS Meter,确认有没有掉帧。如果有,再用Performance面板录一段,找到罪魁祸首。
举个例子。有一次我做一个卡片翻转动画,感觉有点卡。打开FPS Meter一看,掉到40fps。录了一段Performance,发现每次翻转都触发了重排。原因是我用了rotateY但没加will-change。加上之后,直接升到60fps。
小技巧:Performance面板里,看「Summary」底部的「Rendering」耗时。如果超过5ms,说明有优化空间。
1.5 总结:记住这三句话
- 重排最贵,重绘次之,合成最便宜。
- 每帧只有16.67ms,别浪费在重排上。
- 工具是眼睛,学会看Performance和FPS Meter。
好了,这一章就到这里。下一章咱们聊「硬件加速与合成层」,我会告诉你什么时候该用will-change,什么时候用了反而坏事。
公众号:蓝海资料掘金营,微信deep3321