CSS プロパティのアニメーションにかかるパフォーマンスのコストは、プロパティにより異なります。また、高コストな CSS プロパティのアニメーションは、ブラウザがスムーズなフレームレートを確保しようと努力するために jank が発生する場合があります。
フレームレートやウォーターフォールは CSS アニメーションにおいてブラウザが何を行っているかを明らかにして、パフォーマンスの問題の診断を支援します。
CSS アニメーションでは複数のキーフレームを指定して、それぞれのキーフレームではアニメーションの特定の段階における要素の外見を定義するために CSS を使用します。ブラウザは、それぞれのキーフレームから次のキーフレームへ遷移することでアニメーションを作成します。
JavaScript を使用して要素のアニメーションを行うのに比べて、CSS アニメーションは簡単に作れます。またブラウザはいつフレームを描画するかをより制御でき、また必要に応じてフレームを破棄できますので、パフォーマンスが高くなります。
しかし CSS プロパティを変更するためのパフォーマンスコストは、プロパティにより異なります。高コストな CSS プロパティのアニメーションは、ブラウザがスムーズなフレームレートを確保しようと努力するために jank が発生する場合があります。
CSS レンダリングのウォーターフォール
CSS が変更されたときにブラウザがページを更新するためのプロセスは、以下のステップで構成されるウォーターフォールで説明できます:
- スタイルを再計算: 要素の CSS プロパティが変更されるたびに、ブラウザは算出スタイルを再計算しなければなりません。
- レイアウト: 続いて、要素の位置や形状を計算するために算出スタイルを使用します。この操作は "レイアウト" と名付けられていますが、"リフロー" とも呼ばれます。
- 描画: そして、ブラウザはスクリーンに要素を再描画しなければなりません。最後のステップはこの流れで示していません。ページは複数のレイヤーに分割され、それぞれを独立して描画した後に、"コンポジション" と呼ばれるプロセスで合成されます。
この流れが完了しなければスクリーンを更新できませんので、ひとつのフレーム内に一連の操作を収めなければなりません。毎秒 60 フレームが、アニメーションがスムーズに見えるレートとして広く受け入れられています。毎秒 60 フレームのレートのために、ブラウザが一連の操作を実行する時間として 16.7 ミリ秒が与えられます。
CSS プロパティのコスト
レンダリングのウォーターフォールにおいて、一部のプロパティは他のプロパティに比べて特にコストが高くなります:
プロパティの種類 | コスト | 例 |
---|---|---|
要素の形状や位置に影響を与えるプロパティ。これらはスタイルの再計算、レイアウト、再描画を発生させる。 | ||
形状や位置への影響はないが、個別のレイヤーでは描画されないプロパティ。レイアウトは発生しない。 |
||
個別のレイヤーで描画されるプロパティは、再描画が発生しない。更新はコンポジションで制御される。 | transform opacity |
CSS Triggers の Web サイトで、各 CSS プロパティでどれだけのウォーターフォールが発生するかをまとめています。WebKit 固有の情報ですが、ほとんどはすべての最新ブラウザで同じです。
例: margin と transform
本章では、ウォーターフォールが margin
を使用したアニメーションと transform
を使用したアニメーションの違いを、どのように明らかにできるかを示します。
このシナリオは、margin
を使用したアニメーションは例外なく悪いアイデアであると納得させる意図はありません。サイトを描画するためにブラウザが何を行っているかをツールがどのようにして明らかにするか、およびパフォーマンスの問題の診断や解決のためにその情報をどのように適用できるかを示すものです。
自身でも試してみたい場合は、デモ Web サイトがこちらにあります。サンプルは以下のようなものです:
ここには 2 つのコントロールがあります。アニメーションを開始/停止するボタンと、margin
のアニメーションまたは transform
のアニメーションを選択するラジオボタンです。
ページ上には複数の要素を置いており、それらに linear-gradient
の背景と box-shadow
を追加しています。これは、双方のプロパティは描画のコストが比較的高いためです。
動画版のウォークスルーも用意しています:
margin を使用したアニメーション
"Use margin" を選択したままでアニメーションを開始して、パフォーマンスツールを開いて記録を始めましょう。記録時間は数秒だけでかまいません。
最初の記録を開きます。どのような結果になるかはマシンやシステム負荷に大きく依存しますが、おそらく以下のようになるでしょう:
ここでは 3 つの視点で示しています: (a) ウォーターフォールの概要、(b) フレームレート、(c) タイムラインの詳細 です。
ウォーターフォールの概要
これは、ウォーターフォールをコンパクトに表示したビューです。
緑色が圧倒的に多いことは、描画に多くの時間を費やしていることを示しています。
フレームレート
これは、フレームレートを表示します。ここでは平均フレームレートが 46.67fps であり、目標の 60fps をかなり下回っています。さらに悪いことにフレームレートが何度も 10 から 20 fps 台に低下しており、グラフがぎざぎざになっています。特にユーザとの対話が加わると、スムーズなアニメーションではなくなるでしょう。
ウォーターフォール
記録表示領域の残りの部分で、ウォーターフォールを表示します。ウォーターフォールをスクロールすると、以下のようなパターンが見られるでしょう:
これはレンダリングのウォーターフォールを表します。それぞれのアニメーションフレームで、すべての要素のスタイルを再計算してからレイアウト処理を 1 回実施して、再描画を行います。
ここでは、描画が特にパフォーマンスへ悪影響を与えていることがわかります。前出のスクリーンショットでは描画処理をハイライトしており、この処理は 13.11 ミリ秒かかっていることが右側のボックスでわかります。すべての処理に割り当てられた時間は 16.7 ミリ秒しかありませんので、高いフレームレートを維持できないのは驚くことではありません。
ここでインスペクタを使用して box-shadow を削除すると、描画時間にどのような影響があるかを実験できます。しかし次は、margin
の代わりに transform
を使用して高コストな描画を完全になくす方法を見ていきます。
transform を使用したアニメーション
Web ページのラジオボタンを "Use transform" に切り替えて、新たに記録してみましょう。すると、以下のようになるでしょう:
ウォーターフォールの概要
margin を使用した場合と比べて緑色がとても少なく、また桃色がとても多くなっています。桃色はレイアウトやスタイルの再計算でしょう。
フレームレート
margin を使用した場合と比べて、良好であるように見えます。平均値は 60fps に近く、また開始付近で 1 回落ち込んでいることを除けば高いフレームレートを維持しています。
ウォーターフォール
タイムラインビューで、フレームレートが向上した理由が示されています。margin を使用した場合と比べて、レイアウトや (この例ではさらに重要な) 描画に少しも時間を費やしていません:
この例では transform
を使用することでサイトのパフォーマンスが著しく向上しており、またどのようにおよびなぜ向上したかを、パフォーマンスツールで示すことができました。