CSS の描画時間とページ レンダリングの重み

はじめに

ブラウザの仕組みなどにこだわっている方なら、最近 Chrome の GPU による高速レンダラ/複合処理について詳しく解説した記事が公開されているのをご存じでしょう。まず、Chrome の高速レンダリング: レイヤモデルは、Chrome でレイヤの概念がどのように使用されるかを示す優れた入門編です。さらに掘り下げた内容については、Chrome の GPU 高速合成で、Chrome でページをレンダリングする際に GPU と合わせてこれらのレイヤを使用する仕組みをご覧ください。

哲学的な疑問

3D 用のソフトウェア ラスタライザの作成に長い時間を費やしてきた経験から、ページの描画時にいくつかの CSS プロパティのパフォーマンスが異なるべきだということが明らかになりました。たとえば、小さな画像を画面にラスタライズすることは、任意の形状にドロップ シャドウを描画するとはまったく異なるアルゴリズム処理です。そこで問題となったのは、さまざまな CSS プロパティがページのレンダリング ウェイトに与える影響です。

私の目標は、大量の CSS プロパティ/値をペイント時間別に分類することで、どのタイプの CSS プロパティが他よりもパフォーマンスが高いかを把握できるようにすることでした。そのために、ダクトテープとバブルガムを使用して、CSS のペイント時間を数値化して可視化する自動化を記述しました。これは次のように機能しました。

  • 個々の HTML ページのスイートを生成します。各ページには、単一の DOM 要素と、それにアタッチされた CSS プロパティの組み合わせが含まれます。
  • ページごとに次のような自動化スクリプトを実行します。
    • Chromeを起動
    • ページの読み込み
    • ページの Skia Picture を作成する
    • Skia Benchmark で取得した Skia 画像をそれぞれ実行してタイミングを取得する
  • すべてのタイミングをまとめて、その数字に驚くようにしてください。(この部分は重要です...)

この設定では、一連の HTML ページを生成します。各ページには、CSS のプロパティと値の一意の組み合わせが含まれています。たとえば、次の 2 つの 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>

以下は、前の例のバリアントとして、放射勾配値のみを変更するものです。

<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 Picture (*.SKP) が取得され、ページの描画に使用された Skia コマンドが評価されます。各 HTML ファイルに対して SKP ファイルが生成されたら、別のバッチを実行して *.SKP ファイルを push し、Skia Benchmark アプリケーション(Skia ソースコードからビルド)を通じてそのページのレンダリングに要した平均時間を出力します。

データの評価

これで、一連の CSS プロパティのペイントにかかる時間を大まかにグラフ化できるようになりました。あるいは、CSS プロパティをペイント パフォーマンスでスタック ランク ランキング化することもできます。次の大きなグラフは Chrome 27 ベータ版で取得されたもので、このプロセスで得られた時間データがすべて示されています。Chrome の高速化と高速化に伴い、データはすべて変更される場合があります。

テストのすべての順列のタイミング

各縦棒は、CSS プロパティの組み合わせが 1 つあるページのペイント時間を表します(100 倍に拡大。このグラフの実際のスケール値は 0.1.56 ミリ秒です)。きれいな線がたくさんありますが、この形式ではあまり役に立たず、有用なトレンドを見つけるためにデータ マイニングを行う必要があります。

まず、一部の CSS プロパティは他のプロパティよりも単純にレンダリング費用が高いという証拠を見つけます。たとえば、DOM 要素にドロップ シャドウを描画するには、よりレンダリングしやすい不透明度とは対照的に、スプラインなどの厄介なものを使用したマルチパス操作が必要になります。

CSS プロパティが 1 つしかない要素のペイントにかかる時間

さらに興味深いことに、複数の CSS プロパティを組み合わせると、各要素の合計よりも描画時間が長くなることがあります。オブザーバーの観点からは、これは少し奇妙で、2.2C ではなく A+B = C と予想されます。たとえば、box-shadowborder-radius-stroke を追加します。

テストのすべての順列のタイミング

この機能の非常に興味深い点は、box-shadow プロパティ自体だけでなく、その特定の値の順列であるということです。たとえば、値にバリエーションがある box-shadow : 50%border-radius をグループ化した例を以下に示します。

テストのすべての順列のタイミング

データを見ると、この状態はしばらく続きます。さまざまな奇妙な組み合わせがたくさんあり、私のテストスイートはすべてに触れることはほとんどありません。興味深い結果を生み出す可能性があるテストと組み合わせはまだたくさんあります。

ページのレンダリング ウェイトを確認する

デベロッパーは、ページ上の各要素のレンダリング時間をトラッキングする機能を利用して、ページのレンダリングの重みを評価し、それがサイトの応答性にどう影響するかを評価できます。始めるためのヒントをいくつかご紹介します。

  1. Chrome デベロッパー ツールで Chrome の連続ペイントモードを使用すると、どの CSS プロパティで費用が発生しているかを把握できます。
  2. CSS のレビューを既存のコードレビュー プロセスに組み込み、パフォーマンスの問題を特定します。グラデーションやシャドウなど、コストが高いことがわかっているものを使用している CSS の場所を探します。本当にこれが必要なのか、自分に問いかけてみてください。
  3. 判断に迷う場合は、必ずパフォーマンスの改善に取り組みましょう。ユーザーは、列のパディングの幅を覚えていないかもしれませんが、サイトを訪問したときの感触を覚えます。

最後に

このテストで特に興味深い点の一つは、Chrome のバージョンごとにタイミングが変化し続けることです(高速化されることが望ましいです)。ブラウザ ソフトウェアの対象となる領域は絶えず変化しています。今日は遅いが、明日は速くなる可能性がある。この記事では、box-shadow: 1px 2px 3px 4px にすでに border-radius:5 が設定されている要素を配置することを回避できます。しかし、さらに重要な点は、CSS プロパティがページのペイント時間に直接影響するということです。

参照