怎样减少页面的回流和重绘
减少对 dom 的操作
- 当需要进行多个 dom 的增删改查时,避免直接对单个 dom 进行操作
<ul id="box"></ul>
<script>
// 例1-使用 createDocumentFragment 方法创建虚拟的 dom 对象,将新 dom 需要修改的对象进行复制,然后对创建的 dom 进行相应的修改,最终在把 dom 与旧 dom 进行替换
// 这样的能将对 dom 的多次修改合并为一次,大大减少了回流和重绘的次数
let box = document.querySelector('#box')
let test = document.createDocumentFragment()
for (let i = 0; i < 5; i++) {
let li = document.createElement("li")
li.appendChild(document.createTextNode(i))
test.appendChild(li)
}
box.appendChild(test)
// 例2-把需要修改的 dom 隐藏,修改完成后再将 dom 重新显示
// 使用 display: none 后渲染树中将不再渲染当前 dom,所以多次操作也不会多次触发回流和重绘
let box = document.querySelector('#box')
box.style.display = 'none';
for (let i = 0; i < 5; i++) {
let li = document.createElement("li")
li.appendChild(document.createTextNode(i))
box.appendChild(li)
}
</script>
使元素脱离文档流
由于页面中有时候会有一部分元素是有持续性的动画效果的,所以会一直触发回流和重绘,此时可以使这些元素脱离文档流,以此减少页面回流和重绘的次数;
使用浮动( float )、相对定位( position: relative )、绝对定位( position: absolute )可以使元素脱离文档流;
避免访问或减少访问某些属性
浏览器的渲染队列机制会通过队列将会触发回流或重绘的操作进行存储,等到一定的时间或一定的数量时再执行这些操作;
但是某些操作会导致浏览器强制刷新队列,如:offsetTop、offsetLeft、offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle、getBoundingClientRect;
浏览器为了获取最新的页面信息,需要立即执行队列里的所有操作,如果频繁使用上述方法,就会频繁的触发回流和重绘;
所以需要尽量减少或避免使用上述方法 / 属性
避免对 css 进行单个修改
// 避免对 style 进行多次
let box = document.querySelector('#box')
div.style.width = '20px';
div.style.backgroundColor = '#555';
// 可以使用 cssText 将多次合为一次
div.style.cssText += "; width: 20px;";
// 或者添加 class
div.className += " newBox";
will-change( 兼容性不好 )
MDN:CSS 属性 will-change 为web开发者提供了一种告知浏览器该元素会有哪些变化的方法,这样浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作。 这种优化可以将一部分复杂的计算工作提前准备好,使页面的反应更为快速灵敏。
注意事项:
- 不要将 will-change 应用到太多元素上,这样会消耗太多浏览器的资源,导致页面响应缓慢;就像物业原来只管理一栋楼,如果忽然变成管理十栋楼,那么就会导致管理不过来的情况;
- 避免将 will-change 直接写在 css 中,尽量在元素发生变化前去设置它;
PS:
想要了解浏览器解析并渲染页面的过程,可以看我这一篇文章 浏览器解析并渲染页面的过程