不必要な塗料を避ける - GIF アニメーション版

滑らかなフレームレートを実現するには、特にモバイルでペイントを避けることが重要です。しかし、珍しい場所でも塗料が詰まることもあります。この記事では、アニメーション GIF によって不要なペイントが発生する理由と、適用できる非常にシンプルな修正について説明します。

何重もの可愛らしさ

ご存じのように、最新のブラウザは DOM 要素のグループをレイヤと呼ばれる個別の「画像」にペイントすることがあります。ページ全体に 1 つのレイヤが存在する場合もあれば、数百のレイヤ、まれに数千のレイヤが存在することもあります。

DOM 要素が 1 つのレイヤにグループ化され、いずれかの要素が視覚的に変化した場合、変更された要素だけでなく、変更された要素に重なるレイヤ内の他のすべての要素もペイントする必要があります。あるものを別の物の上にペイントすると、上書きされたピクセルは実質的に「永久に失われる」ことになります。元のピクセルを元に戻す場合は、再ペイントする必要があります。

そのため、ペイントされるときに、変更されていない他の要素を再ペイントしなくて済むように、1 つの要素を他の要素から分離したい場合があります。たとえば、固定されたページヘッダーとスクロール可能なコンテンツを組み合わせる場合、新しく表示されるコンテンツだけでなく、コンテンツがスクロールされるたびにヘッダーを再ペイントする必要があります。ヘッダーを別のレイヤに配置することで、ブラウザはスクロールを最適化できます。スクロールすると、ブラウザは(おそらく GPU を使用して)レイヤを移動し、どちらのレイヤの再ペイントも回避できます。

レイヤを追加するごとにメモリの消費とパフォーマンスのオーバーヘッドが増加するため、パフォーマンスを維持しながら、ページをできるだけ少ないレイヤにグループ化することが目標です。

アニメーション GIF にはどのような関係があるのでしょうか。

この画像を見てみよう。

4 つのレイヤに分かれたウェブアプリ。
図 1: 4 つのレイヤに分割されたウェブアプリ。

これはシンプルなアプリのレイヤ設定の例です。4 つのレイヤがあり、そのうちの 3 つ(レイヤ 2 ~ 4)はインターフェース要素で、バックレイヤはローダで、たまたまアニメーション GIF です。通常のフローでは、アプリの読み込み中にローダ(レイヤ 1)を表示し、すべての処理が完了したら、他のレイヤを表示します。ただし、重要な点は、アニメーション GIF を非表示にする必要があるということです。

どうして隠さなきゃいけないの?!

お問い合わせいただきありがとうございます。ブラウザが GIF の表示をチェックするだけで、自動的にペイントされることがなくなります。残念ながら、アニメーション GIF が画面上で不明瞭になっているか見えているかを確認する場合、通常はただペイントするよりも高額であるため、ペイントされます。

最良のケースでは、GIF は独自のレイヤにあり、ブラウザは GIF をペイントして GPU にアップロードするだけで済みます。しかし、最悪のケースではすべての要素が 1 つのレイヤにグループ化され、ブラウザはすべての要素を再描画する必要があります。処理が完了したら、すべてを GPU にアップロードする必要があります。ユーザーに GIF を見ることができないにもかかわらず、これらすべてが GIF フレームごとに発生します。

デスクトップでは、CPU と GPU の方が性能が高く、この 2 つの間でデータを転送するための十分な帯域幅があるため、この種のペイント動作はおそらく回避できるでしょう。しかしモバイルでは、ペイントは非常にコストがかかるため、細心の注意を払う必要があります。

影響を受けるブラウザ

よくあるように、動作はブラウザによって異なります。現在、Chrome、Safari、Opera では、GIF が不明瞭になっていても、すべてが再描画されます。一方、Firefox は GIF を不明瞭にするため、再描画の必要がありません。Internet Explorer は依然としてブラック・ボックスであり、IE11 においても F12 ツールはまだ開発中であるため、再描画が行われているかどうかは示されていません。

この問題が発生しているかどうかを確認するにはどうすればよいですか?

最も簡単な方法は、Chrome DevTools の [ペイント長方形の表示] を使用する方法です。DevTools を読み込み、右下の歯車(歯車アイコン)を押し、[Rendering] セクションの [Show paintpaints] を選択します。

Chrome DevTools で [ペイント長方形を表示] を有効にする
図 2: Chrome DevTools で [ペイントする長方形の表示] を有効にする

あとは、次のような赤い長方形を探します。

DevTools の [ペイント レクタングルを表示] は、赤い長方形を使ってアニメーション GIF の問題のヒントとして提示します。
図 3: DevTools の [Show Paint Rectangles] から、赤い長方形のアニメーション GIF 問題に関するヒントが表示される。

画面上の小さな赤いボックスは、Chrome が再描画中であることを示します。ローダー GIF が他の要素の背後に隠されているため、このような赤いボックスが表示された場合は、可視要素を非表示にして、アニメーション GIF が回転したままになっていないかを確認する必要があります。その場合は、CSS または JavaScript をポップして、display: none または visibility: hidden を親要素に適用する必要があります。もちろん、背景画像にすぎない場合は、削除する必要があります。

実際のサイトでこの動作の例については、Allegro をご覧ください。Allegro では、各商品の画像にローダ GIF が含まれています。このローダは、明示的に隠されているのではなく、不明瞭になっています。

おわりに

60 fps を達成するということは、ページのレンダリングに必要なものだけを実行することであり、それ以上のことは行いません。余分な塗料を取り除くことは、この目標を達成するための重要なステップです。アニメーション GIF を実行したままにすると、不要なペイントがトリガーされる可能性があります。これは、DevTools の [ペイントする長方形の表示] ツールを使用すると簡単に見つけてデバッグできます。

子猫ローダーのアニメーション GIF をずっと実行したままにしてたよね?