先讲下概念:
回流:改变页面布局,元素宽高等会引起盒模型尺寸大小变化的属性,包括显示和隐藏等,都会引起浏览器重新计算盒模型大小
重绘:改变元素的外观,尺寸不改变的因素,比如元素的背景颜色,边框颜色字体颜色等。
从概念上我们就可以知道,回流之后肯定要重绘,而重绘不会回流,那么回流的代价就是要比重绘昂贵。
引起回流的具体因素由以下几个方面:
页面首次渲染。
浏览器窗口大小发生改变。
元素尺寸或者位置发生改变。
元素内容变化(文字数量或者图片大小发生改变)。
元素字体大小的改变。
添加或者删除可见的 DOM 元素。
激活 CSS 伪类 (eg: :hover)。
查询某些属性或调用某些方法。
一些常用且会导致回流的属性和方法。
clientWidth、clientHeight、clientTop、clientLeft
offsetWidth、offsetHeight、offsetTop、offsetLeft
scrollWidth、scrollHeight、scrollTop、scrollLeft
scrollIntoView()、scrollIntoViewIfNeeded()
getComputedStyle()
getBoundingClientRect()
scrollTo()
现代浏览器对回流进行过性能优化,当js频繁改变节点元素时,会先放入一个队列中,之后一次性清空队列,从而达到性能上的优化,而遇到以上这些属性时,会立即清空队列,进行回流操作。
回流优化步骤:
1.改变样式时,尽量使用className,不要频繁设置style属性
2.新建节点时,可以先进行节点缓存,创建一个documentFragment,等待节点设置完属性后,再挂载到dom tree上
3.避免使用 table 布局 (尽量不要使用表格布局,如果没有定宽表格一列的宽度由最宽的一列决定,那么很可能在最后一行的宽度超出之前的列宽,引起整体回流造成table可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。)
4.可以间接使用display来控制回流,对频繁操作节点先隐藏,然后操作节点,之后再显示,可以控制回流重绘为两次
5.将需要多次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位;
6.克隆DOM元素到内存中
```
var old = document.getElementById('myElement');
var clone = old.cloneNode(true);
// 一些基于clone的大量DOM操作
...
old.parentNode.replaceChild(clone, old);
```
首次页面渲染的时候注意性能步骤
1. 浏览器载入 HTML 代码,检测到 <head> 中有 <link> 引用外部 CSS 文件,则浏览器立即发送CSS文件请求,获取浏览器返回的CSS文件; (CSS文件合并,减少HTTP请求)
2. 浏览器载入 HTML 中 <body> 部分的代码,并且 CSS 文件已经加载,开始渲染页面;(CSS文件需要放置最上面,避免网页重新渲染)
3. 浏览器在代码中发现一个 <img> 标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码; (图片文件合并,减少HTTP请求)
4. 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码; (最好图片都设置尺寸,避免重新渲染)
5. 浏览器检测到了一个包含JavaScript 代码的 <script> 标签,会立即运行该js代码; (script最好放置页面最下面)
6. js脚本执行了语句,它令浏览器隐藏掉代码中的某个 <div>,突然就少了一个元素,浏览器不得不重新渲染这部分代码; (页面初始化样式不要使用js控制)