浏览器渲染之回流与重绘

207 阅读3分钟

这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」。

Script放在body头部就一定会阻塞吗 一文中有介绍过浏览器的渲染过程,今天主要说一说回流与重绘。

回流

回流也可称作重排,当页面中某些元素大小或位置等信息发生改变时,浏览器会重新计算其位置和几何信息,这个计算过程就叫做回流。

浏览器在加载一个页面时,最少会发生一次回流,也就是初次加载页面的时候。

触发回流

一般影响元素的规模尺寸、布局的样式操作都会触发回流

  • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
  • 用js操作 DOM (添加或删除可见的DOM元素)
  • 元素的位置发生变化
  • 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
  • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
  • 当你获取布局信息的操作的时候,如:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight, 这些属性和方法都需要返回最新的布局信息,所以浏览器会进行回流获取最新的值。

重绘

当我们改变某个元素的背景色、文字颜色、边框颜色等属性时,就会发生重绘,这些变更它不会影响页面布局,也就是说重绘可以单独发生。
但是如果涉及到页面布局,元素大小变更的操作就会引发回流,在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中。

回流一定会触发重绘,而重绘不一定会回流

优化:减少回流和重绘

回流比重绘的代价要更高,而且回流的花销跟render tree有多少节点需要重新构建有关系

  1. 避免逐条改变样式,使用类名去合并样式
  2. transform来做形变和位移
  3. 让要操作的元素进行”离线处理”,处理完后一起更新
  • 使用DocumentFragment进行缓存操作,引发一次回流和重绘;
    使用文档片段(document fragment)在当前DOM之外构建一个子树,再把它拷贝回文档
  • 使用display:none技术,只引发两次回流和重绘;
    先将元素设为display: none(需要1次重排和重绘),然后对这个节点进行多次操作,最后再恢复显示(需要1次重排和重绘)。这样一来,你就用两次重新渲染,取代了更多次的重新渲染。
  • 使用cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;
    在克隆的节点上进行操作,然后再用克隆的节点替换原始节点
  1. 让多次重排的元素脱离文档流(使用 position 属性的 fixed 值或 absolute 值)
  2. 使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘 。