CSS 绘制时间和网页呈现权重

Colt McAnlis
Colt McAnlis

简介

如果您是那种会关注浏览器的工作原理之类的人,那么您应该已经知道,最近有几篇精彩的文章详细介绍了 Chrome 的 GPU 加速渲染程序/合成操作。首先,Chrome 中的加速渲染:层模型简要介绍了 Chrome 如何使用层概念来绘制网页;如需深入了解,请参阅 Chrome 中的 GPU 加速合成,了解 Chrome 如何使用这些层以及 GPU 来渲染网页。

哲学问题

在花费大量时间编写用于 3D 目的的软件光栅化程序后,我发现一些 CSS 属性在绘制网页时应该会表现出不同的性能。例如,将小图片光栅化到屏幕上与在任意形状上绘制阴影是完全不同的算法操作。因此,问题变成了:不同的 CSS 属性如何影响网页的呈现权重?

我的目标是按绘制时间对大量 CSS 属性/值进行分类,以便了解哪些类型的 CSS 属性比其他类型的 CSS 属性更高效。为此,我用胶带和泡泡糖编写了一些自动化脚本,尝试为 CSS 绘制时间添加数字可见性,其运作方式如下:

  • 生成一组单独的 HTML 网页;每个网页包含一个 DOM 元素,以及附加到该元素的一些 CSS 属性排列组合。
  • 运行一些自动化脚本,针对每个网页执行以下操作:
    • 启动Chrome
    • 加载网页
    • 为网页生成 Skia Picture
    • 通过 Skia Benchmark 运行拍摄的每张 Skia 图片,以获取时间
  • 转储所有时间,并惊叹于这些数字。(这一点很重要…)

采用这种设置后,我们会生成一组 HTML 网页,其中每个网页都包含 CSS 属性和值的独特排列组合;例如,下面是两个 HTML 文件:

<style>
#example1 {
    background: url(foo.png) top left / 50% 60%;
    padding: 20px; 
    margin-top: 10px;
    margin-right: 20px; 
    text-align: center;
}
</style>
<div id="example1">WOAH</div>

还有一个更复杂的

<style>
#example1 {
    background-color:#eee;
    box-shadow: 1px 2px 3px 4px black;
    border-radius: 50%;
    background: radial-gradient(circle closest-corner, white, black);
    padding: 20px; 
    margin-top: 10px;
    margin-right: 20px; 
    text-align: center;
}
</style>
<div id="example1">WOAH</div>

下面是上一个示例的变体,其中我们仅更改了 radial-gradient 值:

<style>
#example1 
{
    background-color:#eee;
    box-shadow: 1px 2px 3px 4px black;
    border-radius: 50%;
    background: radial-gradient(farthest-side, white, black);
    padding: 20px; 
    margin-top: 10px;
    margin-right: 20px; 
    text-align: center;
}
</style>
<div id="example1" style="padding: 20px; margin-top: 10px;margin-right: 20px; text-align: center;">WOAH</div>

然后,每个网页都会加载到一个新的 Chrome 实例中(以确保时间不会因网页重新加载中的任何过时状态而偏向),并获取 Skia 图片 (*.SKP) 以评估用于绘制网页的 Skia 命令。为每个 HTML 文件生成 SKP 文件后,我们会再运行一批作业,通过 Skia Benchmark 应用(基于 Skia 源代码构建)推送 *.SKP 文件,该应用会输出渲染该网页的平均时间。

评估数据

现在,我们已经能够大致绘制一组 CSS 属性的绘制所需时间。或者,我们可以开始按绘制性能对 CSS 属性进行排序。下面是一个使用 Chrome 27 Beta 版生成的大型图表,显示了此进程中的完整时间数据集。请注意,随着时间的推移,Chrome 的速度会越来越快,因此所有数据都可能会发生变化。

测试中所有排列的时间

每个垂直条代表使用单个 CSS 属性组合的页面的绘制时间(放大 100 倍;此图表的真实比例值为 0,1.56 毫秒)。有很多漂亮的线条,但以这种形式显示这些数据没有什么用处;我们需要进行一些数据挖掘,才能发现有用的趋势。

首先,我们发现某些 CSS 属性的渲染开销比其他属性高得多。例如,在 DOM 元素上绘制阴影需要使用样条曲线和其他各种棘手事项进行多通道操作,而不透明度应该更容易渲染。

绘制仅具有 1 个 CSS 属性的元素所需的时间

其次,更有趣的是,CSS 属性的组合绘制时间可能会比各个部分的总和还要长。从观察者的角度来看,这有点奇怪,我们预计 A+B = C,而不是 2.2C。例如,添加 box-shadowborder-radius-stroke

测试中所有排列的时间

真正有趣的是,这不仅仅是 box-shadow 属性本身,而是特定的值排列组合例如,下面显示了 box-shadow : 50%border-radius 的分组,其中包含值变体。

测试中所有排列的时间

查看数据后,我发现这种情况会持续一段时间。有很多奇怪的组合,我的测试套件几乎无法涵盖所有这些组合;仍有大量测试和组合可能会产生有趣的结果

查找页面呈现权重

借助能够跟踪网页上每个元素的呈现时间的功能,开发者可以开始评估其网页呈现权重以及其对网站响应速度的影响;下面列出了一些入门提示

  1. 在 Chrome 开发者工具中使用 Chrome 的连续绘制模式,了解哪些 CSS 属性会导致性能开销。
  2. 将 CSS 审核纳入现有的代码审核流程,以发现性能问题 在 CSS 中查找已知会增加开销的用法,例如渐变和阴影。问问自己,我是否真的需要这些内容?
  3. 如果不确定,请务必选择性能更好的选项。用户可能不会记得列的边距宽度,但会记得访问您网站时的感受。

结语

这项实验最有趣的一点是,随着每个 Chrome 版本的发布,这些时间将继续发生变化(希望越来越快 ;) 浏览器软件是一个不断变化的领域。今天速度慢,明天就可能很快。您可以从本文中了解到,避免在已包含 border-radius:5 的元素中添加 box-shadow: 1px 2px 3px 4px不过,更有价值的结论应该是,CSS 属性会直接影响页面绘制时间。

参考