降低绘制的复杂性并减少绘制区域

Paul Lewis

绘制是填充最终合并到用户屏幕上的像素的过程。它通常是流水线中运行时间最长的任务,因此应尽可能避免使用。

摘要

  • 更改转换或不透明度以外的任何属性始终会触发绘制。
  • 绘制通常是像素流水线中开销最大的部分。请尽可能避免这种情况。
  • 通过层级提升和动画编排来减少绘制区域。
  • 使用 Chrome 开发者工具中的绘制性能分析器来评估绘制复杂性和成本;尽可能降低绘制成本。

布局和绘制是如何触发的

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

完整的像素流水线。

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

不带布局的像素流水线。

使用 Chrome DevTools 快速找出绘制瓶颈

您可以使用 Chrome 开发者工具快速找出正在绘制的区域。打开“渲染”标签页,然后启用绘制闪烁

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

每当绘制时,页面都会闪烁绿色。

宣传移动或淡出元素

绘制并不总是绘制到内存中的单个图片。事实上,浏览器可以根据需要绘制到多个图片或合成层。

表示合成层的表示法。

这种方法的好处在于,可以处理定期重绘的元素或在屏幕上通过转换移动的元素,而不会影响其他元素。这与 Sketch、GIMP 或 Photoshop 等图形软件相同,其中可以处理各个图层并将其叠加在一起以创建最终图片。

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

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

不过,请务必注意不要创建过多图层,因为每个图层都需要内存和管理。如需了解详情,请参阅仅使用合成器属性并管理图层数量部分。

如果您已将某个元素提升到新层,请使用开发者工具确认这样做是否有助于提升性能。请勿在不进行性能分析的情况下宣传元素。

减少绘制区域

不过,有时即使提升了元素的优先级,仍然需要进行绘制工作。绘制问题的一个重大挑战是,浏览器会将两个需要绘制的区域合并在一起,这可能会导致整个屏幕重新绘制。例如,如果您在页面顶部有一个固定标题,并且在屏幕底部绘制了内容,则整个屏幕最终可能会重新绘制。

减少绘制区域通常是指协调动画和转场效果,使其不重叠太多,或者想办法避免为网页的某些部分添加动画。

简化绘制复杂性

绘制屏幕部分所需的时间。

在绘画方面,有些东西的价格比其他东西高。例如,与模糊处理相关的任何内容(例如阴影)的绘制时间都比绘制红色方框要长。不过,在 CSS 方面,这并不总是显而易见的:background: red;box-shadow: 0, 4px, 4px, rgba(0,0,0,0.5); 看起来并不一定具有截然不同的性能特征,但实际上确实如此。

如上图所示,借助绘制性能分析器,您可以确定是否需要考虑其他方法来实现效果。自问是否可以使用更便宜的样式或替代方法来实现最终结果。

请尽可能避免在动画期间进行绘制,因为每帧 10 毫秒通常不足以完成绘制工作,尤其是在移动设备上。