前端面试---回流重绘

296 阅读3分钟
  • 回流(layout,reflow):一般意味着元素的内容,结构,位置或尺寸发生了变化,需要重新计算样式和渲染树
  • 重绘,意味着元素发生的改变只是影响了元素的一些外观之类的时候(比如背景色,边框颜色,文字颜色等),此时只需要应用新样式绘制这个元素就可以了

【回流的成本开销要高于重绘,而且一个节点的回流往往导致子节点以及同级节点的回流,所以要尽量避免回流】

【回流一定伴随着重绘】

为什么会引起回流?

1.页面渲染初始化

2.DOM结构改变,比如删除了某个节点

3.render变化,比如减少了padding

4.窗口resize

5.内容改变

6.元素本身的尺寸发生改变

7.获取某些属性会引起回流

  • offset(top/left/height/width)
  • scroll(top/left/width/height)
  • client(top/left/width/heigth)
  • width,height
  • 调用了getComputeStyle()或者IE的currentStyle
  • 改变字体也会引发回流

【回流一定伴随着重绘,重绘可以单独出现】

【优化方案】

  • 减少逐项更改样式,最好一次性更改style,或者将样式定义为class并一次性更新
  • 避免循环操作dom,创建一个documentFragment或div,在它上面应用所有的dom操作,最后在把它添加在window.dcoument
  • 避免多次读取offset等属性,无法避免则将他们缓存到变量
  • 将复杂的元素绝对定位或固定定位,使得他们脱离文档流,否则回流代价会很高

最小化重绘和重排

  • 使用cssText属性实现改变多个样式
  • 切换类名

批量修改DOM

  • 隐藏元素,进行修改后,然后显示该元素
  • 使用文档片段创建一个子树,然后拷贝到文档中
  • 将原始元素拷贝到一个独立的节点中,操作这个节点,然后覆盖原始节点

缓存布局信息

将offset等属性信息存储起来

如何减少回流

CSS

  • 避免使用table布局
  • 尽可能在DOM树的最末端改变class
  • 避免设置多层内联样式
  • 将动画效果应用到position属性为absolute或fixed元素上
  • 避免使用CSS表达式(例如:calc())

JS

  • 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性
  • 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后在把它添加到文档中
  • 也可以先为元素设置display:none,操作结束后再把它显示出来,因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘
  • 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来
  • 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流

浏览器的优化

  • flush队列:浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次