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>

1 つのビューに新しい要素を追加します。これにより、スタイル、レイアウト、ペイントがトリガーされます。

    <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 つの値をサポートする「contains」というキーワードを含む新しいプロパティです。

  • layout
  • paint
  • size
  • style

これらの値を使用すると、ブラウザが実行する必要のあるレンダリング作業の量を制限できます。それぞれの値を詳しく見ていきましょう。

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

レイアウトのコンテインメントは、おそらく contain: paint と合わせて、コンテインメントの最大のメリットです。

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

ここでコンテインメントを有効にすると、要素の数がドキュメント全体ではなくごく少数に減り、ブラウザの不必要な作業を大幅に削減でき、パフォーマンスが大幅に向上する可能性があります。

Paint(次を含む: Paint)

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

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

サイズ(包含: サイズ)

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

サイズの包含は、サイズに関して子要素に依存しないようにするための一帯一式です。しかし、それだけではパフォーマンス上のメリットはあまりありません。

スタイル(Contain: style)

要素のスタイルを変更すると DOM ツリーに及ぼす影響を予測しにくい場合もあります。一例として、CSS カウンタなどが挙げられます。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 が自社のニーズに合っていない場合は、厳格な封じ込めを回避策として扱う必要があります。

どうしたらよいか教えてください

Containment は、ページ内で分離したままにするものをブラウザに示すための優れた方法です。Chrome 52 以降でお試しいただき、感想をお聞かせください。