简化绘制复杂性并减少绘制区域

绘制是将像素填充到最终合成到用户屏幕上的过程。它通常是管道中所有任务中最耗时的,并且如果可能的话,应尽可能避免。

摘要

  • 更改除 transform 或 opacity 之外的任何属性始终会触发绘制。
  • 绘制通常是像素管道中最昂贵的部分。尽可能避免使用它。
  • 通过图层提升和动画编排来减少绘制区域。
  • 使用 Chrome DevTools 绘制分析器来评估绘制的复杂性和成本;尽可能减少。

布局和绘制是如何触发的

如果您触发布局,您将始终触发绘制,因为更改任何元素的几何形状意味着其像素需要修复!

The full pixel pipeline.

如果您更改非几何属性(如背景、文本颜色或阴影),您也可以触发绘制。在这些情况下,将不需要布局,并且管道将如下所示

The pixel pipeline without layout.

使用 Chrome DevTools 快速识别绘制瓶颈

您可以使用 Chrome DevTools 快速识别正在绘制的区域。打开“渲染”标签页,然后启用 Paint Flashing

启用此选项后,每当发生绘制时,Chrome 都会将屏幕闪烁为绿色。如果您看到整个屏幕闪烁绿色,或者屏幕的某些区域您认为不应该被绘制,那么您应该进一步深入研究。

The page flashing green whenever painting occurs.

提升移动或淡出的元素

绘制并不总是在一个内存中的单个图像中完成。事实上,如果需要,浏览器可以将内容绘制到多个图像或合成器图层中。

A representation of compositor layers.

这种方法的好处是,可以处理经常重绘或在屏幕上使用 transform 移动的元素,而不会影响其他元素。这与 Sketch、GIMP 或 Photoshop 等艺术软件包相同,在这些软件包中,可以处理各个图层并将它们相互合成以创建最终图像。

创建新图层的最佳方法是使用 will-change CSS 属性,该属性在所有主要的现代浏览器引擎中都可用。使用 transform 值,will-change 将创建一个新的合成器图层

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

但是,必须注意不要创建太多图层,因为每个图层都需要内存和管理。有关此内容的更多信息,请参阅坚持仅合成器属性并管理图层计数部分。

如果您已将元素提升到新图层,请使用 DevTools 确认这样做是否为您带来了性能优势。不要在没有分析的情况下提升元素。

减少绘制区域

然而,有时,尽管提升了元素,但仍然需要进行绘制工作。绘制问题的一个巨大挑战是浏览器将两个需要绘制的区域联合在一起,这可能会导致整个屏幕被重绘。因此,例如,如果您在页面顶部有一个固定标题,并且屏幕底部正在绘制某些内容,则整个屏幕最终可能会被重绘。

减少绘制区域通常需要协调您的动画和过渡,以尽量减少重叠,或者找到避免动画页面某些部分的方法。

简化绘制复杂性

The time taken to paint part of the screen.

在绘制方面,有些东西比其他东西更昂贵。例如,任何涉及模糊效果的东西(例如阴影)都比绘制红色方框花费更长的时间。然而,就 CSS 而言,这并不总是显而易见的:background: red;box-shadow: 0, 4px, 4px, rgba(0,0,0,0.5); 看起来性能特征并没有太大的不同,但实际上它们有。

如之前的屏幕截图所示,绘制分析器可让您确定是否需要寻找其他方法来实现效果。问问自己是否可以使用更便宜的样式集或替代方法来达到您的最终结果。

在可能的情况下,您始终希望避免在动画期间进行绘制,因为您每帧拥有的 10 毫秒通常不足以完成绘制工作,尤其是在移动设备上。