# 回流和重绘
# 浏览器渲染过程
先请今天的主角“回流”和“重绘”在后台等一下,我们先来看看浏览器渲染页面的过程,不要跳过这个重要的部分啊~
当浏览器得到页面的时候,就开始了它的渲染过程:
- 解析HTML,构建DOM树(包括了发起http请求来获取链接的内容)
- 解析CSS
- 合并DOM树和CSS规则树,生成reader树
- 布局render树(Layout/reflow),计算元素的位置,大小
- 绘制render树,绘制页面像素信息
上面就是大致的流程了,进行一点简单的解释 ###构建DOM树
- 单个节点的构建经过了
Bytes -> characters -> tokens -> nodes -> object model
的过程 - 整个树的构建利用了栈结构,当一个元素的所有子节点构建完成后才去构建下一个兄弟节点(类似深度优先遍历树)
# 构建CSSOM树
当计算每个节点样式的时候,浏览器会根据优先级从低到高的顺序设置这个节点的属性,从全局属性开始,一直寻找到这个节点的具体属性。这个CSSOM会部分替换浏览器自己的默认样式表。
# 生成render树
这个渲染的过程是从DOM的根节点开始进行render过程,在这个过程中会跳过不占据空间的节点,比如设置了display:none
的元素,不包括那些有大小但设置了visibility:hidden; opacity:0;
的元素。
# reflow的触发
- 页面第一次渲染
- DOM树发生变化(添加DOM节点、添加内容)
- 元素位置或大小变化
- 浏览器窗口大小变化
- 获取属性(这个影响不在于改变了页面,而是破坏了浏览器的进行的批处理回流优化)
一些属性和方法
- clientWidth、clientHeight、clientTop、clientLeft
- offsetWidth、offsetHeight、offsetTop、offsetLeft
- scrollWidth、scrollHeight、scrollTop、scrollLeft
- scrollIntoView()、scrollIntoViewIfNeeded()
- getComputedStyle()
- getBoundingClientRect()
- scrollTo()
# repaint的触发
- 回流必定会引起重绘
- 颜色,透明度,字体等属性的改变会引起重绘
**一个明显的结论:**回流比重绘代价更高
# 优化方法
浏览器本身是有一定的优化策略的,比如维护一个引起回流 / 重绘的队列,将所有引起回流重绘的操作放入队列,进行批处理。这样就能让多次操作变成一次操作,从而提升效率。同时,如果某些页面内容的改变很重要,想要第一时间完成,也可以写代码强行提前队列操作。
日常注意点:
- 将多次页面样式改变合并成一次操作
- 将需要多次重排的元素,设置为absolute或者fixed,元素脱离了文档流,不会影响别的元素
- 对一个有多个层次的dom节点,构建完成之后再插入页面中,而不要一步一步添加
- 可以先把元素display:none,改变内容完成之后再diaplay:block