Skip to content

【综合】回流和重绘(重排) #23

@Dliling

Description

@Dliling

简述回流和重绘之前,先来说一下浏览器的渲染过程:

  1. 解析HTML结构,生成DOM树,解析CSS,生成CSSOM树
  2. DOM树和CSSOM树合并后生成渲染树
  3. 渲染树只包含渲染网页所需的节点
  4. 根据视口大小,布局计算每个对象的精确位置和大小
  5. 最后一步是绘制,使用最终渲染树将像素渲染到屏幕上

参考web
看到第三步,只包含渲染网页所需的节点,如script、link等是不包括的,还有通过CSS隐藏的节点,如display:none。但是opacitye和visibility隐藏的节点,是会在渲染树上的,因为它们虽不可见,但是却占据物理空间。

回流
第四步中,计算每个对象的精确位置和大小,这个计算的阶段就是回流。即页面因为布局、元素大小位置等改变需要重新构建,就是回流。
每个页面至少经过一次回流,即初始化页面时候的第一次加载。

何时发生回流

  1. 添加或删除可见的DOM元素
  2. 元素的位置变化,如发生位移等
  3. 元素的尺寸变化,如大小、内外间距、边框等
  4. 内容变化较大,如文字变为图片等
  5. 初始化页面的第一次渲染
  6. 浏览器的窗口尺寸变化

现代的浏览器都是聪明的,自己有一些优化。每次修改时,不是立即操作,而是缓存在队列中,按照一定的时间顺序去执行。但是当获取offsetTop等位置大小信息时,会实时获取最新值。

重绘(重排)
有些元素需要更新属性,如背景色等,只影响元素外观,不影响大小和位置,即页面布局的,称为重绘。

由上面可知,回流必定引起重绘,但重绘不一定引起回流。

如何减少回流重绘

  1. 利用class名替换行内样式的依次赋值,或者使用cssText
// bad
el.style.padding = '10px';
el.style.margin = '10px';

// good
el.addClass('box');
el.style.cssText += 'padding: 10px; margin: 10px;';
  1. 批量修改DOM
    (1) 使元素脱离文档流
    (2)对其进行修改
    (3)将元素带回文档中

如何让DOM脱离文档流:
a. 先将元素隐藏,修改后再重新显示
b. 利用代码片段(document.createDocumentFragment)在当前DOM之外构建一个子树,操作后再拷贝回文档
c. 将原始元素拷贝到一个脱离文档的节点中,修改后再替换原来元素

  1. 避免多次读取offsetTop等属性,即那些需要立即操作DOM的数据,无法避免时进行缓存。
  2. CSS硬件加速,使用transform、opacity、filters动画时不会引起回流重绘。但是对background-color还是会引起。
  3. 比较复杂的动画效果,让其脱离文档流

想详细了解css硬件加速,可移步这里
参考你真的了解回流和重绘吗

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions