浏览器渲染过程
- HTML代码被HTML解析器解析成DOM树
- CSS代码被css解析器解析成CSSOM树
- 结合DOM树与CSSOM树,生成渲染树
- 生成布局(flow),即将所有渲染树的所有节点进行平面合成
- 将布局绘制(paint)在屏幕上
在这些过程中,生成布局与布局绘制最耗费性能,因此我们应该减少不必要的这两种操作.
重绘
重绘: 我们对DOM的修改造成元素样式的改变,但并未造成元素几何属性的变化(比如修改元素的背景色或字体颜色)。因此浏览器并不需要重新生成布局,只会重新绘制,这个过程就叫做重绘
重排
重排: 我们对DOM的修改造成了元素几何属性的变化(比如元素的位置或元素的宽高)。浏览器会重新生成布局,并重新进行绘制。所以重排会造成重绘,而重绘不一定会重排。
什么时候会触发回流或重绘?
-
添加或删除可见的DOM元素
-
元素的位置发生变化
-
元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
-
内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。
-
页面渲染初始化
-
浏览器的窗口resize尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
-
最复杂的一种:获取某些属性,引发回流
(1) offset(Top/Left/Width/Height)
(2) scroll(Top/Left/Width/Height)
(3) cilent(Top/Left/Width/Height)
(4) width,height
(5) 调用了getComputedStyle()或者IE的currentStyle
如何减少重绘与重排
- 减少DOM操作
例如: 在ul中插入多个li
一般操作:通过for循环不断创建li,并将其添加到ul中,但这样操作每次for循环都会造成重排,非常浪费性能.
<ul id="ul">
<li></li>
</ul>
<script>
var uls = document.getElementById('ul')
for(let i = 0;i<=5;i++){
var li = document.createElement('li')
uls.appendChild(li)
}
</script>
优化操作: 先将UL设置为display:none,再对其进行操作,因为display:none上的DOM操作不会引发回流和重绘
<ul id="ul">
<li></li>
</ul>
<script>
var uls = document.getElementById('ul')
ul.display = 'none'
for(let i = 0;i<=5;i++){
var li = document.createElement('li')
uls.appendChild(li)
}
ul.display = 'block'
</script>
- 批量修改DOM元素
例如: 给div添加样式
<div id="id">
这是测试数据
</div>
<script>
var Div = document.getElementById('id')
Div.style.color = 'red'
Div.style.backgroundColor = 'green'
Div.style.fontSize = '24px'
</script>
优化写法:避免使用JS一个样式修改完接着改下一个样式,最好一次性更改CSS样式,或者将样式列表定义为class的名称
<style>
.add{
color: red;
background-color: green;
font-size: 24px;
}
</style>
<div id="id">
这是测试数据
</div>
<script>
var Div = document.getElementById('id')
Div.classList.add('add')
</script>
- 减少使用以下几何属性: offsetTop,scrollTop,clientTop