浏览器回流和重绘?
回流必将引起重绘,而重绘不一定会引起回流。**
https://juejin.cn/post/6844903569087266823
重绘
repaint,就是浏览器得知元素产生了不影响排版的情况下后对这个元素进行重新绘制的过程。例如我们改变了元素的颜色,加个下划线等(outline, visibility, color、background-color等, 代价是高昂的,因为浏览器必须验证DOM树上其他节点元素的可见性)。
重绘发生的场景
重绘是指在布局和几何大小都不变得情况下,比如次改一下background-color,或者改动一下字体颜色的color等。
回流
浏览器得知元素产生了对文档树排版有影响的样式变化,对所有受影响的dom节点进行重新排版工作(回流也被称为重排)。
- 其变化涉及到部分页面(或是整个页面)的布局更新
- 一个元素的回流可能会导致了其所有子元素以及DOM中紧随其后的节点、祖先节点元素的随后的回流。
回流发生的场景
-
添加或者删除可见的DOM元素
-
元素位置改变
-
元素尺寸改变——边距、填充、边框、宽度和高度
-
内容改变
-
比如文本改变或者图片大小改变而引起的计算值宽度和高度改变
- 比如用户在input框中输入文字,文本或者图片大小改变而引起的计算值宽度和高度改变;
页面渲染初始化
- 比如用户在input框中输入文字,文本或者图片大小改变而引起的计算值宽度和高度改变;
-
-
页面渲染初始化
-
浏览器窗口尺寸改变——resize事件发生时
-
计算offsetWidth和offsetHeight属性
-
设置style属性的值
var s = document.body.style; s.padding = "2px"; // 回流+重绘 s.border = "1px solid red"; // 再一次 回流+重绘 s.color = "blue"; // 再一次重绘 s.backgroundColor = "#ccc"; // 再一次 重绘 s.fontSize = "14px"; // 再一次 回流+重绘 // 添加node,再一次 回流+重绘 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局) document.body.appendChild(document.createTextNode('abc!'));
如何减少回流和重绘
-
css优化
- 避免使用table布局,可能很小的一个小改动会造成整个 table 的重新布局。
- 尽可能在DOM树的最末端改变class,回流是不可避免的,但可以减少其影响。尽可能在DOM树的最末端改变class,可以限制了回流的范围,使其影响尽可能少的节点。
- 避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多。
- 将动画效果应用到position属性为absolute或fixed的元素上。
- 避免使用CSS表达式(例如:calc())。
- 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局)
- CSS3 硬件加速(GPU加速),使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘 。但是对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。
-
javascript优化
1. 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。 2. 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。 3. 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
合成渲染
合成渲染,听着可能有些陌生,但是你肯定用过。对于transform/opacity 这两种变换,浏览器不会用repaint/reflow处理,而是在已经渲染好的元素基础上进行附加工作。例如一个黑底色的div,往右飞100px, 传统JS过程是对每次修改left值后重新画一个div。而如果我们用transform:translate(0,100px) ,transition:2s 浏览器则是把这个绘制好的div单独放在一个画面层再平移这个层过去,div的几何形状,颜色不会再重复计算,而是保留在这个图层中。
提升为合成层简单说来有以下几点好处:
- 合成层的位图,会交由 GPU 合成,比 CPU 处理要快
- 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
- 对于 transform 和 opacity 效果,不会触发 layout 和 paint
- 坚持使用 transform 和 opacity 属性更改来实现动画。
- 使用
will-change
或translateZ
提升移动的元素。 - 避免过度使用提升规则;各层都需要内存和管理开销。
提升动画效果的元素
合成层的好处是不会影响到其他元素的绘制,因此,为了减少动画元素对其他元素的影响,从而减少 paint,我们需要把动画效果中的元素提升为合成层。
提升合成层的最好方式是使用 CSS 的 will-change 属性。从上一节合成层产生原因中,可以知道 will-change 设置为 opacity、transform、top、left、bottom、right 可以将元素提升为合成层。
#target {
will-change: transform; //兼容性不好
}
//对于那些目前还不支持 will-change 属性的浏览器
//目前常用的是使用一个 3D transform 属性来强制提升为合成层
#target {
transform: translateZ(0);
}
处理动画合成器单独处理的属性。
》目前只有两个属性符合条件: transforms
和 opacity
:
上一篇: php面向对象三大特性
下一篇: windows批处理——学习笔记