Paint是填充像素并且最后合成在用户的屏幕上的过程。
通常是在管道中耗费最大的,你要尽可能的避免使用paint。
- 动画中使用除了transform和opacity的动画属性都将触发paint
- paint是像素管道中耗费最大的部分,所以避免使用之
- 在层提升(layer promotion)和编配动画的时候减少layer区域
- 使用Chrom DevTools的paint模块来计算paint的复杂度和耗费:减少你能减少的
如果你触发了layout你就一定触发了paint,因为改变元素的几何形状意味着元素的像素需要修改。
你可以触发paint如果你改变了不是几何性质的属性,例如background,text color,亦或shadow。
在这些情况下layout将不会被触发,管道看上去像下面这样:
使用 Chrome DevTools 快速检测paint瓶颈
在chrome DevTools中的console栏目选中rendering,勾选show paint rectangels
注意上面的钩钩选择之后将会导致chrome将会捕捉paint发生的地方,并用绿色表示。
如果有些地方你认为不应该发生paint,那么你可以深入优化。
当你想获得paint的更多信息,你可以在Timeline中选择paint,记住只有选择paint之后浏览器才能记录相关信息,否则将不会检测paint。
现在,你需要做recording。recording结束之后选择一帧,在下面的summary中点击paint profiler,如下图:
点击之后你可以看见哪里被paint了,这个paint花费了多长时间和这个paint调用的individual paint 。
上面检测方法让你同时检测了paint的复杂度和paint的区域。
你可以根据结果来优化。
对需要移动和消退的元素进行提升(promote)
paint不总是在在内存中paint成一张image。事实上,浏览器paint成多张image,亦或多张合成器层(compositor layers),如果有必要的话。
好处是元素被再次paint亦或在屏幕上使用transform属性进行移动时,可以不影响其他元素。
这就像绘画软件Sketch,GIMP亦或Photoshop,一个层中进行的操作不会影响另一个层,所有的层一个接着一个相互结合并创建除了最后的图片。
创建新的层的最好方式是使用css属性 will-change
。 在Chrome和Opera和Firefox浏览器中起作用,并且因为will-change属性值transform,将会创建一个新的构造器层。
.moving-element { will-change: transform; }
对于不支持will-change属性的浏览器,但是为了创建layer,所以你必须(误)用3D transform来强迫创建一个新的layer,适用于Safari和Mobile Safari等。
.moving-element { transform: translateZ(0); }
注意不要创建太多的layer,因为一个layer既占内存也需要管理。如果你提升了元素(promote a element)来创建新的层,使用DevTools来确定这样做将会给你一个性能上的提升。
不要不进行检测就直接提升元素。
减少paint区域
对paint而言巨大的挑战就是浏览器将两个需要paint的元素结合在一起,而且这将会导致整个屏幕被重新paint。
所以,尽可能减少paint区域。
简化paint的复杂度
当谈到paint的时候,有些行为消耗很大。
比如,任何包含模糊效果(例如一个阴影)代码将会比画一个红色的box花费更长时间。
css中的background:red和box-shadow:0,4px,4px,rgba(0,0,0,0.5)在执行上对性能有很大不同的影响。
上面paint profiler允许你决定你为了达到最终相同的结果,你是否需要替换已有方案来达到最优性能:你要在动画中尽量变paint操作,且每一帧的paint都会大于10ms,特别是在移动手机上将会耗时更多。