回流与重绘

153 阅读3分钟

前言

当你了解了“回流与重绘”的触发原理、触发条件,你就可以对你的代码做出合适的优化操作,从而提高相关性能

渲染原理

webkit的渲染流程

过程描述:

  • 解析HTML,生成DOM树
  • 解析CSS,生成CSSOM树
  • 将CSSOM合并至DOM树,去除不可见元素,生成Render-tree(渲染树)
  • layout,根据生成的渲染树,生成渲染信息,得到节点的几何位置(位置、大小)
  • Painting,根据渲染树以及回流得到的几何信息,将Render-tree的每个像素渲染在屏幕上

回流

定义:在Layout阶段,计算元素在视口区域(viewport)内的确切位置和大小,计算这些值的过程称为回流、布局、或者重排。或者说,就是当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。

HTML 采用基于流的布局模型,从根渲染对象(即html)开始,递归遍历部分或所有的框架层次结构,为每一个需要计算的渲染对象计算几何信息,大多数情况下只要一次遍历就能计算出几何信息。但是也有例外,比如table的计算就需要不止一次的遍历。

每个页面至少会发生一次回流,就是在页面第一次加载的时候。

会触发回流的操作

  • 页面首次渲染

  • 浏览器窗口大小发生变化

  • 元素的尺寸或者位置发生变化

  • 元素内容变化(文字数量或图片大小等等)

  • 元素的字体发生变化

  • 添加或者删除可见的元素(注意:如果是删除本身就display:none的元素不会发生重排;visibility:hidden的元素显示或隐藏不影响重排)

  • 激活CSS伪类,例如:hover

  • 查询某些属性、或者调用某些方法

    具体有以下属性:

    • clientWidthclientHeightclientTopclientLeft

    • offsetWidthoffsetHeightoffsetTopoffsetLeft

    • scrollWidthscrollHeightscrollTopscrollLeft

    • scrollIntoView()scrollIntoViewIfNeeded()

    • getComputedStyle()

    • getBoundingClientRect()

    • scrollTo()

重绘

当元素一部分属性发生变化,如背景图片改变文字颜色改变等,不导致页面布局发生改变而需要重新渲染的过程叫做重绘

flush队列

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

当访问这些属性(获取值)的时候,为获取到真实值(队列里的操作无论是否与该属性相关),浏览器会强制清空队列。 这些属性有:clientWidthclientHeightclientTopclientLeftoffsetWidthoffsetHeightoffsetTopoffsetLeftscrollWidthscrollHeightscrollTopscrollLeftwidthheightgetComputedStyle()getBoundingClientRect()

优化

  • 利用css类名替换直接修改样式
  • 避免频繁修改样式,可一次性修改style
  • 避免使用tabel布局
  • 使用文档片段(document fragment)
  • 隐藏元素,应用修改,重新显示(先将元素隐藏,此时元素不在 render tree上,修改其样式不会发生 重绘和回流,修改完毕再将元素显示出来这样只触发两次回流和两次重绘)