问题说明
一次偶然使用paint flashing中发现,项目中页面进行滚动操作时所有的元素竟然都在repaint
0.0 于是决定稍微研究一下
排查过程
首先看了看实现代码,确实没有什么骚操作,就是普通的一个scroll: auto。随手看了看滚动时的火焰图
在滚动的过程中确实一直在paint操作(里面绿色的都是),但是并无fps卡顿。
虽然这种不影响性能,但还是想看看能否优化一下。
浏览器主要执行步骤
-
JavaScript:包含与视觉变化效果相关的js操作。包括并不限于:dom更新、元素样式动态改变、jQuery的animate函数等。
-
Style:样式计算。这个过程,浏览器根据css选择器计算哪些元素应该应用哪些规则,然后将样式规则落实到每个元素上去,确定每个元素具体的样式。
-
Layout:布局。在知道对一个元素应用哪些规则之后,浏览器即可开始计算它要占据的空间大小及其在屏幕的位置。
-
Painting:绘制。绘制是填充像素的过程。它涉及绘出文本、颜色、图像、边框和阴影,基本上包括元素的每个可视部分。绘制一般是在多个表面(通常称为层)上完成的。(paint和draw的区别:paint是把内容填充到页面,而draw是把页面反映到屏幕上)
-
Composite:合成。由于页面的各部分可能被绘制到多层,由此它们需要按正确顺序绘制到屏幕上,以便正确渲染页面。对于与另一元素重叠的元素来说,这点特别重要,因为一个错误可能使一个元素错误地出现在另一个元素的上层。
从上面来看,只需要让滑动元素composite成一个层级,那应该就可以阻止重绘
对于composite,还发现了一篇非常nice的文章:无线性能优化:Composite
will-change
首先想到的自然是will-change,说实话,MDN上对will-change的描述感觉有些模糊,先来尝试一下 加上will-change后的效果
看起来确实没问题了。
但是看看will-change的描述:
既然也没出现丢帧的情况,那是没必要使用will-change,但是以后想要极限优化可以使用
el.addEventLister('mouseenter', () => { el.style.willChange = 'scroll-position' });
el.addEventLister('mouseleave', () => { el.style.willChange = 'unset' });
存在问题
有些web的scroll应该没有使用will-change也没存在上述重绘情况,之后遇到还有待跟进