DOM的重绘和回流
重绘:元素样式的改变(但宽高、大小、位置等不变)
如 outline, visibility, color、background-color等
回流:元素的大小或者位置发生了变化(当页面布局和几何信息发生变化的时候),触发了重新布局,导致渲染树重新计算布局和渲染
如添加或删除可见的DOM元素 ;
元素的位置发生变化;
元素的尺寸发生变化;
内容发生变化(比如文本变化或图片被另一个不同尺寸的图片所替代);
页面一开始渲染的时候(这个无法避免);
因为回流是根据视口的大小来计算元素的位置和大小的,所以浏览器的窗口尺寸变化也会引发回流.…
注意:回流一定会触发重绘,而重绘不一定会回流
前端性能优化之:避免DOM的回流
1.放弃传统操作dom的时代,基于vue/react开始数据影响视图模式 mvvm / mvc / virtual dom / dom diff…
2.分离读写操作 (现代的浏览器都有渲染队列的机制)
offsetTop、offsetLeft、offsetWidth、offsetHeight、clientTop、clientLeft、clientWidth、clientHeight
scrollTop、scrollLeft、scrollWidth、scrollHeight、getComputedStyle、currentStyle…会刷新渲染队列
//=>渲染队列机制导致引发一次回流(读写分离)
navBox.style.width = '100px';
navBox.style.height = '100px';
console.log(navBox.clientWidth);
//=>触发两次
navBox.style.width = '100px';
console.log(navBox.clientWidth);
navBox.style.height = '100px';
3.样式集中改变
div.style.cssText = ‘width:20px;height:20px;’
div.className = ‘box’;
4. 缓存布局信息
//运行一次获取一次,回流一次
div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';
//=>改为
//获取一次,暂时存放起来,只需要回流一次
var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';
5.元素批量修改
文档碎片:createDocumentFragment
模板字符串拼接
//=>10次回流
for (let i = 0; i < 10; i++) {
let span = document.createElement('span');
navBox.appendChild(span);
}
//改为 示例一
//创建一个节点
//因为文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来更好的性能。
let frag = document.createDocumentFragment();
for (let i = 0; i < 10; i++) {
let span = document.createElement('span');
frag.appendChild(span);
}
navBox.appendChild(frag);
//示例二 模板拼接
let str = ``;
for (let i = 0; i < 10; i++) {
str += `<span></span>`;
}
navBox.innerHTML = str;
6.动画效果应用到position属性为absolute或fixed的元素上(脱离文档流)
尽量不要用 margin,
7.CSS3硬件加速(GPU加速)
比起考虑如何减少回流重绘,我们更期望的是,根本不要回流重绘;transform \ opacity \ filters … 这些属性会触发硬件加速,不会引发回流和重绘…
可能会引发的坑:过多使用会占用大量内存,性能消耗严重、有时候会导致字体模糊等
8.牺牲平滑度换取速度
每次1像素移动一个动画,但是如果此动画使用了100%的CPU,动画就会看上去是跳动的,因为浏览器正在与更新回流做斗争。每次移动3像素可能看起来平滑度低了,但它不会导致CPU在较慢的机器中抖动
9.避免table布局和使用css的javascript表达式
避免使用table布局,在布局完全建立之前,table需要很多关口,table是可以影响之前已经进入的DOM元素的显示的元素。即使一些小的变化和会导致table中所有其他节点回流。
避免使用css的JavaScript表达式,该规则较过时,但是个好主意。因为每次都需要重新计算文档,或部分文档、回流。