TL;DR
CSS Containment という新しい仕様によって、ブラウザが行うスタイル、レイアウト、描画の範囲を制限できるようになります。
Containament 仕様では次の構文と値が定義されています。
contain: none | strict | content | [ size || layout || style || paint ]
CSS Containment は Chrome 52、Opera 40 で実装されました(Firefox も支持を表明しています)。ぜひ使ってみて、どうだったかを教えてください!
contain プロパティ
Web アプリや複雑な Web サイトを開発するとき、スタイル、レイアウト、描画をどう抑えるかがパフォーマンス上の課題になります。多くの場合 DOM の全体が計算の「スコープ内」になるため、Web アプリにおいて自己完結した「ビュー」を作るのが難しいのです。これは、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 (封じ込め)です。
contain プロパティ
CSS Containment は contain
という新しいプロパティに以下の値を指定し使用します。
layout
paint
size
style
各値はそれぞれ、ブラウザがするべきレンダリングの行いを制限します。それぞれの値についてみてみましょう。
レイアウト (contain: layout)
This value turns on layout containment for the element. This ensures that the containing element is totally opaque for layout purposes; nothing outside can affect its internal layout, and vice versa. Containment 仕様
訳:この値は要素に対し、レイアウトの封じ込めを有効にします。これにより、要素がレイアウト上不透明(opaque)であることが保証されます。つまり要素外のものが封じ込められた要素に影響することはありませんし、逆もまた同様です。
レイアウトの封じ込めは contain: paint
とともに、最も恩恵を受けるものでしょう。
基本的にレイアウトはドキュメント全体がスコープになるため、DOM の大きさに比例して大きくなります。つまり、要素の left
プロパティを変更したとすると(プロパティは一例です)、DOM 内のすべての要素に対しチェックが働く可能性があります。
封じ込めを有効にすると、考慮すべき要素の数がドキュメント全体から片手で数えるくらいに減るでしょう。これにより、ブラウザが無駄な仕事をする必要がなくなり、パフォーマンスが大きく向上する可能性があります。
描画 (contain: paint)
This value turns on paint containment for the element. This ensures that the descendants of the containing element don’t display outside its bounds, so if an element is off-screen or otherwise not visible, its descendants are also guaranteed to be not visible. Containment 仕様
訳:この値は要素に対し、描画の封じ込めを有効にします。これにより、子孫要素が指定された要素の領域外に表示されないことが保証されます。もし指定された要素が画面外、もしくは非表示となる場合、子孫要素も表示されません。
描画にスコープを設けることは、レイアウトに続きとても有益な封じ込めでしょう。描画の封じ込めは、適用された要素を切り取るようなものです。しかし副作用もあります。
- 絶対配置され、さらに固定配置された要素のコンテナブロックのような挙動をとる ― つまり
contain: paint
内の要素は、ドキュメントをはじめ、親の要素と同じように配置されません - スタッキングコンテキストになる ― これにより、
z-index
などが作動し、子要素も新しく生成されたコンテキストに沿ってスタックされます - フォーマティングコンテキストになる ― これにより、たとえば描画の封じ込めを指定したブロックレベル要素がある場合、それは独立したレイアウト環境として扱われます。つまり、要素の外側のレイアウトが要素内の子に影響することは基本的にありません
大きさ (contain: size)
The value turns on size containment for the element. This ensures that the containing element can be laid out without needing to examine its descendants. Containment 仕様
訳:この値は要素に対し、大きさの封じ込めを有効にします。これにより、指定された要素が子孫要素の内容を調べずにレイアウトされることが保証されます。
contain: size
は、要素の子が親要素の大きさに影響しないことを意味し、計算もしくは指定された大きさが使用されます。結果、contain: size
を指定しても、大きさを指定しなかった場合(直接もしくは Flexbox のプロパティ経由で)、要素は 0px × 0px で表示されます。
サイズの封じ込めは大きさの決定に子要素を考慮しないことを二重に保証するものです。しかし、これ自身だけではパフォーマンスにあまり寄与しません。
スタイル (contain: style)
This value turns on style containment for the element. This ensures that, for properties which can have effects on more than just an element and its descendants, those effects don’t escape the containing element. Containment 仕様
訳:この値は要素に対し、スタイルの封じ込めを有効にします。これにより、要素や子孫以外にも影響するプロパティにおいて、その影響が当該要素外に漏れ出さないことを保証します。
要素のスタイルを変更した場合、DOM ツリーの上方にどう影響するのかを予想するのは大変でしょう。ひとつの例としてCSS のカウンタがあります。子のカウンタを変更すると、ドキュメント中にある同じ名前を持つカウンタの値に影響するのです。contain: style
を指定すると、包含要素を超えてスタイルの変更が伝わることはありません。
contain: style
はスタイルにスコープをもたらすものではありません(スタイルのスコープは Shadow DOM によってもたらされます)。ここでの封じ込めは該当するツリーの一部に対しスタイルの変更を制限するものであり、スタイルの宣言を制限するものではありません。
strict と content
値のキーワードは contain: layout paint
のように組み合わせても使えます。こうするとその挙動のみを適用します。ただ、 contain
プロパティにはほかにもう2つ値があります。
contain: strict
はcontain: layout style paint size
と同じですcontain: content
はcontain: layout style paint
と同じです
要素の大きさがわかっているとき(もしくは大きさを保持したいとき)には、strict
がよいでしょう。しかし strict
を大きさ抜きで指定した場合、大きさの封じ込めが効果として含まれているため、要素が 0px × 0px で表示されるかもしれないことに注意してください。
いっぽうで、content
はスコープにとても寄与します。大きさを指定する必要もありません。
この2つの中では基本的に contain: content
を検討したほうがよいでしょう。contain: content
では不十分な場合に、その回避策として strict
を使うべきです。
試してみてください
封じ込めは、ページ上のどの箇所を孤立させたいかをブラウザに示すとてもよい仕組みです。Chrome 52 以降で試して、どうかを教えてください!
関連リンク
Translated By: