FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
362 stars 39 forks source link

[译]渲染性能优化之Paint篇 #199

Open FrankKai opened 4 years ago

FrankKai commented 4 years ago

原文链接:https://developers.google.com/web/fundamentals/performance/rendering/simplify-paint-complexity-and-reduce-paint-areas

绘制指的是将像素填充到用户屏幕上的过程。通常它是所有任务里消耗时间最长的任务,也是尽可能要避免的任务。

从哪些方面考虑提升Paint阶段的渲染性能优化?

触发Layout和Paint

如果你触发了layout,通常紧随其后的就是触发patin,因为改变元素的几何形状意味着它的pixels需要fixing! image

如果你改变的是非几何的属性,例如background,text-color,shadows,虽然不会触发layout,但是可以触发paint。 image

使用Chrome Devtools快速定位paint瓶颈

可以使用Chrome DevTools的Rendering面板,开启Paint flashing,去查看当前需要Repaint的区域。 口Paint flashing Highlights areas of the page (green) that need to be repainted. May not be suitable for people prone to photosensitive epilepsy.

image

在我项目中开启Paint flashing后的一次尝试,这里我修改的是table cell的background。

当有paint发生时,屏幕上的paint区域会变成绿色。 如果你发现全屏都paint或者有一块不在你预期内的区域变绿了,那这个时候你就要注意了,想办法把这种没必要的repaint避免掉。

提升移动或者淡出的元素

在内存上,paint通常不是直接输出一个单独的图片。 事实上,如果有必要的话,浏览器会绘制成多个图片,或者多个layer。 image

这样做的好处是:元素重新paint,或者通过transform在屏幕上移动时,可以不用影响到其它的元素。 这其实类似于Sketch,GIMP或者Photoshop中图层的概念,它们的layer可以单独处理,并且组合在彼此之上,从而创建出最终的图像。

最好的创建一个新的layer的方式是使用will-change css属性。在Chrome,Opera和Firefox。可以创建一个新的合成层。

.moving-element {
    will-change: transform;
}

对于不支持will-change的浏览器来说,可以使用translateZ去强制创建一个layer:

.moving-element {
    transform: translateZ(0);
}

谨记不要创建太多的layer,以内每个layer都会占用内存,需要管理。更多关于layer的可以查看:坚持使用合成器-only的属性和管理layer数量

如果提升了一个元素到一个新的layer,使用DevTools去确定性能是否有问题。 谨记不要在没有分析的情况下就提升element。

减少绘制区域

有些时候,即使提升了元素,paint仍然是必需的。paint的最大问题是浏览器联接两个需要paint的区域,联接后整个屏幕再发生重新绘制。 所以,如果你有一个fixed定位的header在页面的顶部,然后有一个东西在屏幕的底部paint,那么整个屏幕可能都需要被重新paint。

注意:注意:在高DPI屏幕上,fixed位置的元素被自动提升到它们自己的合成层。在低DPI设备上不是这样的,因为提升将文本呈现从亚像素转换为灰度,而layer提升需要手动完成。

减少绘制区域通常是协调动画和过渡以减少重叠的情况,或者找到避免页面某些部分动画化的方法。

简化绘制复杂性

如果真正需要paint,有一些操作是比其他的要更加复杂的。 例如,包含blur的任何(比如一个shadow)要比绘制一个红色的box,需要更长的时间。 在css中,有时候这并不明显:background: redbox-shadow: rgba(0,0,0,0.5) 0 4px 4px,;看起来没有性能差别,但其实是有的。

上面的paint profiler 允许你决定你是否需要看其他方法来达到效果。问问你自己,是否有可能使用一套更不耗性能的的styles或其他方式来达到你的最终结果。

特别避免在animation期间绘制,因为每帧10ms的时间通常不够长,无法完成绘制工作,特别是在移动设备上。