画面外コンテンツのレンダリングをスキップして、最初の読み込み時間を短縮。
公開日: 2020 年 8 月 5 日
content-visibility
プロパティを使用すると、ユーザー エージェントは、要素のレンダリング作業(レイアウトやペイントなど)を必要になるまでスキップできます。レンダリングがスキップされるため、コンテンツの大部分が画面外にある場合、content-visibility
プロパティを使用すると、ユーザーの最初の読み込みが大幅に高速化されます。また、画面上のコンテンツに対する操作も速くなります。便利ですね。
CSS の制限
CSS コンテインメントの主な目標は、ページの他の部分から DOM サブツリーを予測可能な形で分離することで、ウェブ コンテンツのレンダリング パフォーマンスを改善することです。
基本的に、デベロッパーはページのどの部分がコンテンツのセットとしてカプセル化されているかをブラウザに指示できます。これにより、ブラウザはサブツリー外の状態を考慮することなくコンテンツを推論できます。どのコンテンツ ビット(サブツリー)に分離されたコンテンツが含まれているかを把握することで、ブラウザはページのレンダリングを最適化できます。
CSS 制限には 4 つのタイプがあり、それぞれが contain
CSS プロパティの有効な値です。これらの値は、スペース区切りの値のリストに組み合わせることができます。
size
: 要素のサイズ制限により、要素の子孫を調べることなく要素のボックスをレイアウトできます。つまり、要素のサイズのみが必要な場合は、子孫のレイアウトをスキップできます。layout
: レイアウトの制限とは、子孫がページ上の他のボックスの外部レイアウトに影響しないことを意味します。これにより、他のボックスのレイアウトのみを行う場合は、子孫のレイアウトをスキップできます。style
: スタイルの制限により、子孫だけでなく、要素の外部にも影響する可能性があるプロパティ(カウンタなど)が要素から漏れないようにします。これにより、他の要素のスタイルのみを計算する場合は、子孫のスタイル計算をスキップできます。paint
: ペイントの制限により、包含ボックスの子孫が境界外に表示されなくなります。要素からはみ出す要素は視覚的に存在できません。要素が画面外にある場合や、表示されていない場合、その子孫も表示されません。これにより、要素が画面外にある場合は、子孫のペイントをスキップできます。
content-visibility
によるレンダリング処理をスキップ
ブラウザの最適化は、適切なセットが指定された場合にのみ開始されるため、どのコンテナ化値を使用するかを判断するのは難しい場合があります。値を試して最適な値を確認することも、content-visibility
を使用して必要な制限を自動的に適用することもできます。content-visibility
を使用すると、デベロッパーは最小限の労力でブラウザが提供する最大のパフォーマンス向上を実現できます。
content-visibility プロパティで指定できる値はいくつかありますが、パフォーマンスをすぐに改善できるのは auto
です。content-visibility: auto
を持つ要素には、layout
、style
、paint
の包含が含まれます。要素が画面外にある場合(ユーザーに関連していない場合 - 関連する要素は、サブツリーでフォーカスまたは選択されている要素です)、size
の制限も適用されます(コンテンツのペイントとヒットテストは停止します)。
これはどういう意味ですか?つまり、要素が画面外にある場合、その子孫はレンダリングされません。ブラウザは、要素のコンテンツを考慮せずに要素のサイズを決定し、そこで停止します。要素のサブツリーのスタイル設定やレイアウトなど、レンダリングのほとんどはスキップされます。
要素がビューポートに近づくと、ブラウザは size
コンテナを追加せず、要素のコンテンツのペイントとヒットテストを開始します。これにより、ユーザーに表示されるタイミングでレンダリング作業を実行できます。
ユーザー補助に関する注意事項
content-visibility: auto
の特長の 1 つは、オフスクリーン コンテンツがドキュメント オブジェクト モデルで引き続き使用できるため、アクセシビリティ ツリーも利用できることです(visibility: hidden
とは異なります)。つまり、読み込みを待ったり、レンダリング パフォーマンスを犠牲にしたりすることなく、ページ上でコンテンツを検索して移動できます。
ただし、display: none
や visibility: hidden
などのスタイル機能を持つランドマーク要素は、ビューポートに表示されるまでブラウザがこれらのスタイルをレンダリングしないため、画面外でもユーザー補助ツリーに表示されます。これらの要素がユーザー補助ツリーに表示されないようにして、混乱を招かないようにするには、aria-hidden="true"
も追加してください。
例: 旅行ブログ
旅行ブログには通常、いくつかの写真と説明的なテキストが含まれる一連の記事が含まれています。一般的なブラウザで旅行ブログに移動すると、次のようになります。
- ページの一部が、必要なリソースとともにネットワークからダウンロードされます。
- ブラウザは、コンテンツがユーザーに表示されるか否かを考慮せずに、ページのすべてのコンテンツにスタイルを設定してレイアウトします。
- ページとリソースがすべてダウンロードされるまで、ブラウザは手順 1 に戻ります。
ステップ 2 では、ブラウザがすべてのコンテンツを処理し、変更されている可能性のあるものを探します。新しい要素のスタイルとレイアウトが更新され、新しい更新の結果として移動した可能性のある要素も更新されます。これはレンダリング作業です。これには時間がかかります。
次に、ブログ内の個々のストーリーに content-visibility: auto
を付けた場合の処理について考えてみましょう。一般的なループは同じです。ブラウザがページのチャンクをダウンロードしてレンダリングします。ただし、手順 2 で実行される作業量が異なります。
content-visibility を使用すると、現在ユーザーに表示されている(画面上にある)すべてのコンテンツのスタイルとレイアウトが設定されます。ただし、画面外に完全に表示されるストーリーを処理する場合、ブラウザはレンダリング作業をスキップし、要素ボックス自体のスタイルとレイアウトのみを行います。
このページの読み込みのパフォーマンスは、画面上のストーリーがすべて表示され、画面外のストーリーごとに空のボックスが表示されている場合と同じになります。これにより、読み込みのレンダリング コストが50% 以上削減されると予想されます。この例では、レンダリング時間が 232 ミリ秒から 30 ミリ秒に短縮されています。パフォーマンスは7 倍向上します。
これらのメリットを享受するためには、どのような作業が必要ですか。まず、コンテンツをセクションに分割します。
次に、セクションに次のスタイルルールを適用します。
.story {
content-visibility: auto;
contain-intrinsic-size: 1000px; /* Explained in the next section. */
}
contain-intrinsic-size
を使用して要素の自然なサイズを指定する
content-visibility
の潜在的なメリットを実現するには、ブラウザがサイズ制限を適用して、コンテンツのレンダリング結果が要素のサイズに影響しないようにする必要があります。つまり、要素は空であるかのようにレイアウトされます。要素に通常のブロック レイアウトで高さが指定されていない場合、高さは 0 になります。
各ストーリーの高さがゼロでない場合、スクロールバーのサイズが変化するため、これは理想的ではありません。
幸い、CSS には contain-intrinsic-size
という別のプロパティがあり、要素がサイズ制限の影響を受けている場合、要素の自然なサイズを効果的に指定できます。この例では、セクションの高さと幅の推定値として 1000px
に設定しています。
つまり、サイズが指定されていない div がスペースを占有するように、1 つの子要素が「intrinsic-size」ディメンションを持つかのようにレイアウトされます。contain-intrinsic-size
は、レンダリングされたコンテンツの代わりにプレースホルダ サイズとして機能します。
contain-intrinsic-size
の auto
キーワードを使用すると、ブラウザは最後にレンダリングされたサイズ(存在する場合)を記憶し、デベロッパーが指定したプレースホルダのサイズではなく、そのサイズを使用します。たとえば、contain-intrinsic-size: auto 300px
を指定すると、要素は各ディメンションで 300px
の固有サイズで開始されますが、要素のコンテンツがレンダリングされると、レンダリングされた固有サイズが保持されます。その後のレンダリング サイズの変更も記憶されます。つまり、content-visibility: auto
が適用された要素をスクロールして画面外にスクロールし直すと、要素は理想的な幅と高さを自動的に保持し、プレースホルダのサイズに戻ることはありません。この機能は、ユーザーがページを閲覧するにつれて、サイズの推定が自動的に改善される無限スクロールに特に役立ちます。
content-visibility: hidden
のコンテンツを非表示にする
レンダリング状態キャッシュのメリットを活用しながら、コンテンツが画面上に表示されるかどうかに関係なくコンテンツがレンダリングされない状態を維持するにはどうすればよいでしょうか。content-visibility: hidden
と入力します。
content-visibility: hidden
プロパティを使用すると、content-visibility: auto
が画面外で使用する場合と同様に、レンダリングされないコンテンツやキャッシュされたレンダリング状態のメリットをすべて享受できます。ただし、auto
とは異なり、画面上のレンダリングは自動的には開始されません。
これにより、要素のコンテンツを非表示にして、後で簡単に表示できるようになります。
要素のコンテンツを非表示にする他の一般的な方法と比較します。
display: none
: 要素を非表示にして、レンダリング状態を破棄します。つまり、要素の非表示を解除するコストは、同じコンテンツを持つ新しい要素をレンダリングするコストと同じです。visibility: hidden
: 要素を非表示にし、レンダリング状態を保持します。ただし、この方法では要素(とそのサブツリー)はページ上の幾何学的スペースを占有し、クリックできるため、ドキュメントから要素が完全に削除されるわけではありません。また、非表示の場合でも、必要に応じてレンダリング状態を更新します。
一方、content-visibility: hidden
は、レンダリング状態を保持しながら要素を非表示にします。そのため、変更が必要な場合、その変更は、要素が再度表示されたとき(つまり、content-visibility: hidden
プロパティが削除されたとき)にのみ行われます。
content-visibility: hidden
の優れたユースケースには、高度な仮想スクロールの実装やレイアウトの測定などがあります。また、シングルページ アプリケーション(SPA)にも適しています。非アクティブなアプリビューは、content-visibility: hidden
を適用して DOM に残しておき、表示を防ぎながらキャッシュに保存された状態を維持できます。これにより、ビューが再びアクティブになったときに、ビューをすばやくレンダリングできます。
Interaction to Next Paint(INP)への影響
INP は、ユーザー入力に確実に応答できるページの能力を評価する指標です。レンダリング処理など、メインスレッドで実行される処理の量が多すぎると、応答性に影響する可能性があります。
特定のページのレンダリング作業を減らすことができる場合は、メインスレッドがユーザー入力に迅速に対応できるようになります。これにはレンダリング作業も含まれます。適切な場所で content-visiblity
CSS プロパティを使用すると、レンダリング作業を減らすことができます。特に、ほとんどのレンダリングとレイアウト作業が行われる起動時に効果的です。
レンダリング作業を減らすことは、INP に直接影響します。content-visibility
プロパティを適切に使用して、画面外要素のレイアウトとレンダリングを遅らせるページでユーザーが操作しようとすると、メインスレッドはユーザーに表示される重要な処理に応答できるようになります。これにより、場合によってはページの INP が向上する可能性があります。
まとめ
content-visibility
と CSS 制限仕様により、CSS ファイルのパフォーマンスが大幅に向上します。これらのプロパティの詳細については、以下をご覧ください。