CSS コンテインメント(Chrome 52)

要約

新しい CSS Containment プロパティを使用すると、ブラウザのスタイル、レイアウト、ペイント作業の範囲を制限できます。

CSS Containment変更前: レイアウトに 59.6 ミリ秒かかる。変更後: レイアウトに 0.05 ミリ秒かかる

いくつかの値を持ち、構文は次のようになります。

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

Chrome 52 以降と Opera 40 以降で利用できます(Firefox で公開サポートされています)。試して、ご利用状況をお知らせください。

contains プロパティ

ウェブアプリ、あるいは複雑なサイトを作成するときは、スタイル、レイアウト、ペイントの効果を制限することがパフォーマンス上の主な課題となります。多くの場合、DOM の全体が計算処理の「対象範囲内」と見なされます。つまり、ウェブアプリで自己完結型の「ビュー」を試すことは困難です。DOM の一部に変更が加わると他の部分に影響する可能性があり、ブラウザに対して対象範囲内のべき部分と範囲外すべき部分を伝える方法がないということです。

たとえば、DOM の一部が次のようになっているとします。

    <section class="view">
      Home
    </section>

    <section class="view">
      About
    </section>

    <section class="view">
      Contact
    </section>

一方のビューに新しい要素を追加すると、スタイル、レイアウト、ペイントがトリガーされます。

    <section class="view">
      Home
    </section>

    <section class="view">
      About
      <div class="newly-added-element">Check me out!</div>
    </section>

    <section class="view">
      Contact
    </section>

ただし、この場合は DOM 全体が実質的にスコープ内に収まっています。つまり、スタイル、レイアウト、ペイントの計算では、要素が変更されたかどうかにかかわらず、すべての要素を考慮する必要があります。DOM が大きいほど、必要な計算量が多くなり、アプリがユーザー入力に反応しなくなる可能性があります。

幸いなことに、最新のブラウザではスタイルの範囲、レイアウト、ペイント作業を自動的に制限する機能がスマート化されています。つまり、何もしなくても処理が速くなっています。

しかし、さらに良いニュースは、スコープの制御をデベロッパーに委ねる新しい CSS プロパティ、Containment です。

[CSS Containment] は、次の 4 つの値をサポートする「Containment」キーワードを持つ新しいプロパティです。

  • layout
  • paint
  • size
  • style

これらの値を使用して、ブラウザで必要なレンダリング処理の量を制限できます。それぞれを詳しく見ていきましょう。

レイアウト(次を含む: レイアウト)

おそらく、レイアウトの包含が、contain: paint と並ぶ最大のメリットです。

通常、レイアウトはドキュメント スコープであり、DOM のサイズに比例してスケーリングされます。そのため、要素の left プロパティを変更する場合は、DOM 内のすべての要素をチェックする必要があります。

ここで包含を有効にすると、要素の数をドキュメント全体ではなくほんの一握りに減らすことができます。ブラウザで不必要な作業を大幅に減らし、パフォーマンスを大幅に改善できます。

塗料(塗料を含む)

スコーピング ペイントも、封じ込めの非常に便利なメリットです。ペイントの封じ込めは基本的に問題の要素をクリップしますが、他にもいくつかの副作用があります。

  • 絶対位置と固定位置の要素の包含ブロックとして機能します。つまり、子は、ドキュメントなどの他の親要素ではなく、contain: paint を持つ要素に基づいて配置されます。
  • スタック コンテキストになります。つまり、z-index などが要素に影響し、子は新しいコンテキストに従って積み重ねられます。
  • 新しい書式設定のコンテキストになります。たとえば、ペイントを含むブロックレベルの要素がある場合、その要素は新しい独立したレイアウト環境として扱われます。つまり、要素の外側のレイアウトは、通常はそれを含む要素の子に影響しません。

サイズ(次を含む: サイズ)

contain: size とは、要素の子が親のサイズに影響を及ぼさないこと、およびその推定サイズまたは宣言されたディメンションが使用されることを意味します。そのため、contain: size を設定したにもかかわらず、要素の寸法(直接または Flex プロパティを介して)を指定しなかった場合、0px x 0px でレンダリングされます。

サイズの包含は、サイズを決定する際に子要素に依存しないようにするためのベルトと中かっこの手法ですが、それだけではパフォーマンス上のメリットはあまりありません。

スタイル(包含: style)

要素のスタイル変更によって DOM ツリーに及ぼす影響が、ツリーの上位に遡ってどのような影響を受けるかを予測するのは困難です。たとえば、CSS カウンタなどでは、子のカウンタを変更すると、ドキュメントの他の場所で使用されている同じ名前のカウンタ値に影響することがあります。contain: style を設定すると、スタイルの変更が、それを含む要素を超えて反映されることはありません。

厳密に言えば、contain: style が提供しないのは、Shadow DOM のようなスコープ スタイル設定です。ここでの包含は、宣言時ではなく、スタイル変更時に考慮されるツリー部分を制限することのみを目的としています。

コンテンツの封じ込めを厳格化

また、contain: layout paint などのキーワードを組み合わせて、それらの動作のみを要素に適用することもできます。ただし、contains には 2 つの追加値もサポートしています。

  • contain: strictcontain: size layout paint と同じであることを意味します。
  • contain: contentcontain: layout paint と同じであることを意味します。

厳密な包含は、要素のサイズが事前にわかっている場合(または、その寸法を予約したい場合)に効果的ですが、サイズを含んでいない厳密な包含を宣言すると、暗黙のサイズ包含によって、要素が 0px x 0px のボックスとしてレンダリングされる可能性があります。

一方、コンテンツの包含では、スコープが大幅に改善されますが、事前に要素の寸法を把握したり指定したりする必要はありません。

2 つのうち、contain: content をデフォルトで使用することをおすすめします。contain: content がニーズに十分ではない場合、厳格な封じ込めを回避策として扱う必要があります。

ご利用方法をお知らせください

封じ込めは、ページ内で分離しておきたいものをブラウザに伝える優れた方法です。Chrome 52 以降でお試しいただき、ご意見、ご感想をお寄せください。