经典面试题:什么是回流和重绘?如何优化?
浏览器渲染一页有两条工作:跑 JS、算 CSS。它们是互斥的。面试里「回流 / 重绘」问的就是:改样式时,浏览器要不要重算几何,要不要重画像素。
回流(reflow):render tree 一部分或全部因为宽高、布局、显示隐藏、或内部文字结构变了,需要重新构建页面。重绘(repaint):宽高、布局、显隐没变,只改外观(颜色、阴影等)。结论:回流必定触发重绘,重绘不一定触发回流。
避免回流的两条大方向:少用会触发布局的属性;把变化关进独立图层,限制计算范围。
一、图层是怎么划分的
DOM 加载完后,浏览器会按一些特殊 CSS(例如 position: absolute | fixed)把页面划成一个个图层。元素在自己图层里变化时,回流和重绘尽量只发生在图层内,减少整页计算。
图层内部大致会:对节点做回流和再布局、算出样式;生成图形和位置;把每个节点画进图层位图;把图层当纹理送到 GPU;再把所有图层合并显示。滥用图层会让合成过多,页面反而卡。图层该给「经常改位置 / 布局」的元素,比如轮播。
| 概念 | 触发条件 | 和对方的关系 |
|---|---|---|
| 回流 reflow | 改宽高、布局、显隐、文字结构 | 一定伴随重绘 |
| 重绘 repaint | 只改外观,几何不变 | 不一定回流 |
| 独立图层 | absolute/fixed、部分 3D transform 等 | 把计算关进局部,但合成有成本 |
二、九条可替换写法
-
用 transform代替 top / left / margin-top / margin-left 这类位移。 -
用 opacity代替 visibility 时,要同时有translate3d或translateZ才能真正避开回流。实验:不加transform: translateZ(0)的 opacity 仍会回流;单用 visibility 往往只重绘;opacity + translateZ/3d 后可以既不回流也不重绘。 -
不要用 JS 给 DOM 设多条样式,改成切一个 className。 -
若必须用 JS 设多条样式,先隐藏再改,改完再显示。 -
不要在循环里读 offsetWidth / offsetHeight / clientWidth / clientHeight。浏览器有回流缓冲栈,写样式会攒一批再刷;反复读几何会强迫立刻刷新栈。把值缓存在循环外。 -
不要用 table 布局:一行甚至一个单元格更新都可能让整表重布局。 -
动画速度按业务需要,不必盲目求快。 -
频繁变化的元素加 transform;视频用 video 标签。 -
必要时开 GPU 加速,但不能滥用。开加速时最好给当前动画元素一个更高的 z-index,人为干扰复合层排序,减少 Chrome 创建多余复合层。
三、什么是 16ms 优化
多数设备刷新率 60 次/秒(1000/60 ≈ 16.6ms)。每一帧要在约 16ms 内画完,超时就会卡。浏览器一帧里大致按下面顺序干活,少做 Layout / Paint,动画才顺:
-
JavaScript:动画、DOM 操作。 -
Style:算出每个 DOM 该套哪些 CSS。 -
Layout:算大小和位置。网页布局是相对的,一个元素动了会连带其它,这个过程叫 reflow。 -
Paint:在多层上画文字、颜色、图、边框、阴影。 -
Composite:按顺序合并图层,显示到屏幕。
一句话总结:回流改几何、重绘改外观;用 transform/opacity+图层代替 top/visibility,避免循环读布局、避免 table 和逐条改 style,把一帧工作压进约 16ms。
转载请注明来源:经典面试题:什么是回流和重绘?如何优化?







