Vitaminaq / interview-collection

前端面试合集
3 stars 0 forks source link

重绘重排,如何避免 #7

Open Vitaminaq opened 2 years ago

Vitaminaq commented 2 years ago

重绘(Repaint):按字面意思理解就是重新绘制。布局没有发生改变,改变那些不会影响元素在网页中的位置的元素样式时,譬如background-color(背景色), border-color(边框色), visibility(可见性),浏览器只会用新的样式将元素重绘一次(这就是重绘,或者说重新构造样式)。

重排(Reflow):按字面意思理解就是重新排列。当DOM变化影响了元素的几何属性(宽、高改变等等),浏览器此时需要重新计算元素几何属性,并且页面中其他元素的几何属性可能会受影响这样渲染树就发生了改变,也就是重新构造RenderTree渲染树。

注意:重排一定会触发重绘,而重绘不一定会重排

触发重排的场景:

1.页面初始渲染。
2.DOM操作(元素添加、删除、修改或者元素顺序的改变)。
3.元素位置、尺寸变化(更改类的属性),元素内容发生变化(如图片、文本)。
4.激活伪类。
5.浏览器窗口动作(拖拽、拉伸等)。
6.添加或者删除样式表。

触发重排的属性和方法:
现代的浏览器都是很聪明的,由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。但是!当你获取布局信息的操作的时候,会强制队列刷新

offsetTop、offsetLeft、offsetWidth、offsetHeight
scrollTop、scrollLeft、scrollWidth、scrollHeight
clientTop、clientLeft、clientWidth、clientHeight
getComputedStyle()
getBoundingClientRect()

如何减少和避免重排:

1,2为假设浏览器不现代也不聪明的情况下。 1.合并多次对DOM和样式的修改。

const el = document.getElementById('test');
el.style.padding = '5px';
el.style.borderLeft = '1px';
el.style.borderRight = '2px';
// 有三个样式属性被修改了,每一个都会影响元素的几何结构,引起重排

// 解决方案 - 使用cssText
const el = document.getElementById('test');
el.style.cssText += 'border-left: 1px; border-right: 2px; padding: 5px;';

// 解决方案 - 修改CSS的class
const el = document.getElementById('test');
el.className += ' active';

2.批量修改DOM:类似于vue那样的,开辟出一个节点副本,做完更新,再一次性替换。

3.减少和避免使用上面能触发重排的属性和方法的使用。

// 优化前每次都会获取offsetWidth
function initP() {
    for (let i = 0; i < paragraphs.length; i++) {
        paragraphs[i].style.width = box.offsetWidth + 'px';
    }
}
// 优化后只会获取一次
const width = box.offsetWidth;
function initP() {
    for (let i = 0; i < paragraphs.length; i++) {
        paragraphs[i].style.width = width + 'px';
    }
}

// 监听节点是否在可视区,常见做法:定时器+getBoundingClientRect
// 可以改用IntersectionObserver,缺点:存在兼容性问题,某些ios机型不支持。

4.对于复杂动画效果,使用绝对定位让其脱离文档流。

5.css3硬件加速(GPU加速)。 常见的触发硬件加速的css属性:

使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起重绘重排 对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。

硬件加速原理:
浏览器首先页面解释成DOM树,DOM树和CSS让浏览器构建渲染树,渲染树包含渲染对象(在页面中需要渲染的元素),每一个渲染对象被分配到一个图层中,每一个图层被更新到GPU,通过transform的层会使用GPU渲染,因此不需要重绘,就像3D图形一样。这个转换是单独处理的。

创建层级的条件:

硬件加速会导致的问题: 1.大部分重要的问题都是关于内存。GPU处理过多的内容会导致内存问题。这在移动端和移动端浏览器会导致崩溃。因此,通常不会对所有的元素使用硬件加速。
2.在GPU渲染字体会导致抗锯齿(-webkit-font-smoothing)无效。这是因为GPU和CPU的算法不同。因此即使最终硬件加速停止了,文本还是会在动画期间显示得很模糊。