NIKKEI TECHNOLOGY AND CAREER

CSS Containment によるパフォーマンス改善

この記事はNikkei Advent Calendar 2020 19日目の記事です。 日経電子版ウェブチームの伊藤です。 この記事では CSS Containment の紹介と電子版での利用例について書きます。

CSS Containment とは

概要

CSS Containment はDOMのレンダリングを開発者側で調整できるようにするパフォーマンス系のプロパティです。 webサイトが効率的にレンダリングされるようユーザーエージェントに伝えることができます。

次のような値を取ります。

contain: none | strict | content | [ size || layout || paint ]

プリミティブな値として size, layout, paint があり、strictcontent はこれらを複合した値のエイリアスで、それぞれ size layout paint, layout paint と等価です。

プリミティブな値は、次のような効果を与えます。

  • size

    • 子孫要素のサイズの計算を省略する
  • layout

    • 要素の外側が内側のレイアウトに影響を与えない。また、逆も然り
    • formatting context を生成する
  • paint

    • 子孫要素をその要素の外側に描画しない

生まれた経緯

このプロパティは当初、 css-overflow-clipping という名前でした。 元々のアイデアは、overflow: hidden よりも厳格に制約を課すことで Paint 時に強い最適化を行うことができるというものです。 overflow: hidden は、はみ出た要素を見えないようにする CSS プロパティですが、この要素は js 側から Element.scrollTop などを使うことでスクロールすることが可能です。 このスクロールが出来ないようにすることで、Paint時のパフォーマンスを上げることができます。

すぐに contain という名前が決まり、Paint時以外にも最適化を行うべく仕様が練られていきます。 こうして size, layout, paint, style がプリミティブな最適化に寄与する値として決まりました。 そして先月、CSS Containment Module Level 1が正式に勧告されました。

styleCSS Counter などの影響を閉じ込めるためのプロパティです。Chrome でバグが多く上がっていたことなどからリスクありとされてしまい、Module Level 1 からは落ちてしまいました。

また、当初のアイデアはoverflow: clip という形で結実しています

電子版での取り組み

電子版ではトップページと記事ページで使用しています。 ここではトップページでこの CSS を使用した際の効果を紹介します。

トップページでは次の画像の赤線で囲った要素に対して contain: content を付けています。

トップページで CSS Containment を使用した領域

この CSS をつける前と後で Paint Time を計測すると、次のようになりました。 計測するたびに大きく変化はするのですが、Paint Time はおおよそ半分の時間で済みます。

Before After
トップページのpaint time(CSS Containment 導入前) トップページのpaint time(CSS Containment 導入後)

また、日経平均株価などのインデックスを表示する箇所では、次のように Paint Flashing を見ると効果が分かりやすくなります。 30秒ごとに HTML Fragment が返ってくる API を叩き innerHTML で差し込むという実装をしているのですが、この CSS プロパティを使うことで Paint を最小限の範囲にしました。

Before After
トップページのインデックスの Paint Flashing(CSS Containment 導入前) トップページのインデックスの Paint Flashing(CSS Containment 導入後)

今後の展開

現在 CSS Containment Module Level 2 の仕様策定が進んでおり、Module Level 1 から大きく変更される点が2つあります。 1つは content-visibility の追加、もう1つは style の追加です。

content-visibility

最も大きいアップデートです。 ブラウザ側でレンダリングの最適化を行うべく策定中の Display Locking API で提案されたプロパティが CSS Containment に入りました。 ここまでで説明したプリミティブな値をブラウザが自動で判別して付けてくれる、といった内容のプロパティです。 Chrome 85 で実装されたことでいくつかのサービスで導入されています。

電子版でも導入を検討しましたが、次の理由で見送りました。

  1. フッターに付けてみたが、Paint Time はほとんど変化しないか、悪化する
  2. フッター以外かつ Above the fold には入らない要素につけると、スクロールバーが意図しない動きをする。contain-intrinsic-size で防げるが、やはり Paint Time が変化しなかった

日経ビジュアルデータにあるような、スクロール及び Paint Time を要するコンテンツに対して使うのが適切だと思います。

style の追加

Module Level 2 では仕様に style が入りました。 しかし先程書いたようにリスクがあるため、strict は Module Level 1 と同じ値のエイリアスになりました。 Chrome ではすでに style が実装されており、strictsize layout paint style のエイリアスとして実装されています。 これを現在の仕様に合わせて size layout paint にする、つまり strict から style を取る実装が入る予定です

終わりに

CSS Containment の説明と電子版での利用事例の紹介を行いました。 Paint Time の最適化は電子版のような SSR を行う比較的シンプルなサービスではパフォーマンス上のボトルネックになることはなく、大きな効果はありません。 様々な最適化を行った上で試してみる価値はあると思います。 LP などのビジュアルコンテンツでは content-visibility による Paint Time 最適化の効果が大きく出ると思います。 ぜひ試していただきたいです。

明日は同じチームの阿部さんによる「ChromeとFastlyのEarlyHintsの効果計測に貢献する」です。

参考

伊藤大晃
ENGINEER伊藤大晃

Entry

各種エントリーはこちらから

キャリア採用
Entry
新卒採用
Entry
短期インターン
Entry