CSS Containment の制約と効能について覚え書き

ある要素内の状態による外界への影響を封じ込めて最適化を促す

CSS Containment Module で定義される contain プロパティは will-change と同じようにブラウザが処理を最適化するために開発者から提供できるユーザーエージェント向けヒントとして機能します。

ヒントの目的はcontain の対象要素が親兄弟に影響を及ばさない独立した部分木であることを宣言し、各種の影響を contain の対象要素の中に封じ込めることです。

使うときは contain プロパティに既定の値として用意された size | layout | style | paint | content | strict のいずれかを指定します。contentstrict は複合指定のエイリアスなので、本文では size layout style paint の4つについて個々の説明をします。

.contained {
  contain: content; /* contain: paint layout style; と同意 */
}

何となく解説している風ですが仕様を眺めながら試したメモであり、厳密にすべての情報を拾っているわけではないので、網羅的な詳細は原文の CSS Containment Module Level 3 を参照してください。

挙動の確認用デモ

とりあえず全てのレパートリを試せるサンプルを用意しました。本記事の公開時点では Chrome または Opera の Blink 勢しかサポートされていないのと、そもそも Draft なので今後どうなのかも定かではありません。下記の埋め込みサンプルは、大きい画面で開いて試した方が良いでしょう。

CodePen - Hello, CSS Containment Playground

See the Pen Hello, CSS Containment Playground by Ayumu Sato (@ahomu) on CodePen.

size — サイズ計算の封じ込め

size は指定された要素のサイズがコンテンツ、子孫要素に影響されなくなることを宣言します。

制約

対象要素のコンテンツが空である状態と同じように、widthheight プロパティなどを指定してサイズを明示しない限り、その要素がサイズを持たなくなります。劇的な最適化ができそうな気もしますが、最適化に対する貢献度はあまり高くないそうです。

最適化にはあまり貢献しないってのは、どのみち子孫要素のレンダリングでレイアウトもサイズ計算もするんだから、親のサイズ計算時に考慮に入れるか入れないかだけで、計算量の殆どは支払ってるってノリ?

効用

最も有益なケースは、内容物の大きさや Viewport サイズなどに基づいてコンテナ要素のサイズを決定するような JavaScript ライブラリを利用時です。コンテナ要素に contain: size が指定されていれば、サイズを変更しても子孫要素のことを気に掛けないので再計算の連鎖、あるいはループを確実に防げるようになります。

また「対象要素が画面外にある場合、他の要素のレイアウトに影響を与えないことが確定しているので中身のレンダリングを遅延できる」ようになります。

layout — レイアウトによる関係性の封じ込め

layout は指定された要素が、親兄弟要素のレイアウトに影響を与えないことを宣言します。

制約

contain: layout の対象要素は Formatting Context を得るので例えば float した要素の回り込みは境界面で途切れます。レイアウト周りなので色々な状況が想定されるのですが、基本的には Formatting Context に関係するトコだけ気をつければ大丈夫かなと思います。詳しくは仕様を参照してください。(投げた)

効用

通常、レイアウトの計算はドキュメント全体を対象に作用しますが「レイアウトの影響範囲が限定されることを明示することで再計算の対象を狭い範囲に限定したり、全体の再計算から除外したりできる」ようになります。

Layout containment is probably the biggest benefit of containment, along with contain: paint. CSS Containment in Chrome 52 – Dev Channel – Medium

ということで後述の paint と並んで強力な最適化をもたらすという位置づけだそうです。

style — スタイル影響の封じ込め

style は指定された要素の外側に(一般的なレイアウト処理以外で)影響を与える可能性がある一部のスタイルの効果を子孫に波及させないようにしたり、子孫要素の中で完結させたりすることを宣言します。

制約

  1. The following properties must have no effect on descendants of the element:
    • break-* (and the related aliases)
    • bookmark-*
    • string-set
  2. The counter-increment, counter-set, flow-from, flow-into, and content (for the purpose of open-quote/etc values) properties must be scoped to the element’s sub-tree. CSS Containment Module Level 3

ほとんどの開発者にとって馴染みのないマイナーなプロパティ(CSS Regions とか混ざってるよ)に限られるような印象ですが、ともかくこれらの CSS について、子孫に影響を与えなくなったり、影響を対象要素の部分木の中に限定したりするようになります。

効用

上記のスタイルに制限を与えることで「 contain: style の対象要素の子孫にプロパティの変更があったとき、その影響が対象要素の外に及ぶことがないことが保証されるので再計算を減らせる」ようになるそうです。

paint —ペイント範囲の封じ込め

paint は指定された要素の境界の外側に子孫要素がペイント(レンダリング)されないことを宣言します。

制約

contain: paint の対象要素は Stacking Context を得るのに加えて、position: absolute または position: fixed な子要素を従えて包含配置の基準ブロックとして振る舞うようになります。また、contain:layout と同様に Formatting Context も得るので例えば float した要素の回り込みは境界面で途切れます。

contain: paint 対象要素の境界よりも外にはみ出る可能性がある子孫要素がいても、対象要素の中へ全て強制的におさまるようになる」と解釈すれば良いでしょう。

効用

子孫要素が外部に影響しないことを保証できるので、対象要素が画面外にあれば Paint 処理を完全にスキップできます。また Stacking Context を得ることで GPU 合成時の巻き込みを避けて、単一の Composite Layer でおさめられることが保証されます。

strict, content — 複合条件のエイリアス

記事の冒頭で少し書いたとおり、contain: strictcontain: size layout style paint と同じであり、contain: contentcontain: layout style paint と同じです。これらの違いについては次の注記に記述されています。

Note: contain: content is reasonably "safe" to apply widely; its effects are fairly minor in practice, and most content won’t run afoul of its restrictions. However, because it doesn’t apply size containment, the element can still respond to the size of its contents, which can cause layout-invalidation to percolate further up the tree than desired. Use contain: strict when possible, to gain as much containment as you can. CSS Containment Module Level 3

contain: content であれば「ほとんどのケースで contain による制約条件の影響を受けずに、安全に contain による恩恵を受けられる」ということです。contain: strict になると size が加わり、子要素によってサイズが変更されなくなるのでより厳しい制約条件になります。strict であってもいわゆるブログパーツやサードパーティウィジェットのラッパー要素などには適用しやすそうです。

参考

内容的には下記のリソースを参考にしています。containment を訳すと封じ込めになるわけですが、何でもかんでも封じ込めと書くと何を封じ込めているのか分からなくなるので、具体的な記述を優先してみました。

余談

参加者募集中です??

追記

Google Developers の記事、和訳あったんかい /(^o^)\