基本概念
DOM树(DOM tree):浏览器解析HTML文本创建的树结构
CSSOM(CSS Object Model):将样式表中的规则映射到页面对应的元素上
渲染树(render tree):CSSOM和DOM树合并成渲染树,只包含渲染网页所需的节点
重排(relayout):在Firefox中被称为reflow(回流),部分或整个渲染树需要重新分析并且节点尺寸需要重新计算
重绘(repaint/redraw):节点的几何属性或样式发生改变,屏幕进行内容的更新,称为重绘
触发重排与重绘的情况
重排
页面第一次渲染 在页面发生首次渲染的时候,所有组件都要进行首次布局,这是开销最大的一次重排
浏览器窗口尺寸改变
元素位置和尺寸发生改变的时候
新增和删除可见元素
内容发生改变(文字数量或图片大小等等)
元素字体大小变化
激活CSS伪类
设置style属性
查询某些属性或调用某些方法,比如说:
offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight
重绘
vidibility
、outline
、背景色等属性的改变
重绘不一定导致重排,重排一定导致重绘
避免或减少重排带来的开销
分离读写操作
div.style.top = "10px";
div.style.bottom = "10px";
div.style.right = "10px";
div.style.left = "10px";
console.log(div.offsetWidth);
console.log(div.offseHeight);
console.log(div.offsetRight);
console.log(div.offsetLeft);
原来的操作会导致四次重排和四次重绘,变换顺序之后只会触发一次重排 在第一个console
的时候,浏览器把之前上面四个写操作的渲染队列都给清空了。因为渲染队列本来就是空的,所以剩下的console
并没有触发重排,仅仅拿值而已。
样式集中改变
通过class
和cssText
进行集中改变样式
缓存布局信息
// bad 强制刷新 触发两次重排
div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';
// good 缓存布局信息 相当于读写分离
var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';
DOM离线
一旦我们给元素设置
display:none
时,元素不会存在于渲染树中,相当于将其从页面“拿掉”,我们之后的操作将不会触发重排和重绘,这叫做DOM的离线化。通过使用DocumentFragment创建一个
dom
碎片,在它上面批量操作dom
,操作完成之后,再添加到文档中,这样只会触发一次重排。<ul id="list"></ul>
const list = document.querySelector('#list'); const fruits = ['Apple', 'Orange', 'Banana', 'Melon']; const fragment = document.createDocumentFragment(); fruits.forEach(fruit => { const li = document.createElement('li'); li.innerHTML = fruit; fragment.appendChild(li); }); list.appendChild(fragment);
将position属性设置为absolute或fixed
position
属性为absolute
或fixed
的元素,重排开销比较小,不用考虑它对其他元素的影响
优化动画
- 把动画效果应用到
position
属性为absolute
或fixed
的元素上,这样对其他元素影响较小 - 启用GPU加速
原文链接
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!