Cumulative Layout Shift の最適化

レイアウトの急な変化を回避してユーザー エクスペリエンスを向上させる方法

Cumulative Layout Shift(CLS)は、3 つのウェブに関する主な指標の 1 つです。ビューポート内での表示コンテンツの移動量と、影響を受ける要素の移動距離を組み合わせて、コンテンツの不安定性を測定します。

レイアウト シフトはユーザーの注意をそらす可能性があります。記事を読み始めたら、突然要素がページ内で移動し、読みにくくなって、読み直さなければならなくなったとします。これは、ニュースを読んでいるときや、[検索] ボタンや [カートに追加] ボタンをクリックしようとしているときなど、ウェブ上でよく見られます。このようなエクスペリエンスは視覚的に不快で、イライラさせます。この問題は、別の要素が突然ページに追加されたりサイズ変更されたりして、可視要素が強制的に移動された場合に発生します。

優れたユーザー エクスペリエンスを提供するには、ページ訪問の 75% 以上で CLS を 0.1 未満にすることを目標としてください。

0.1 未満であれば良好な CLS と見なされますが、0.25 より大きい場合は改善の余地があります。
良好な CLS 値は 0.1 未満です。低速の値は 0.25 より大きい値です。

他の Core Web Vitals は秒単位またはミリ秒単位で測定される時間ベースの値ですが、CLS スコアは、コンテンツの移動量と移動距離の計算に基づく単位のない値です。

このガイドでは、レイアウト シフトの一般的な原因を最適化する方法について説明します。

CLS が低い主な原因は次のとおりです。

  • ディメンションのない画像。
  • 広告、埋め込み、iframe(ディメンションなし)。
  • 広告、埋め込み、iframe など、ディメンションのない動的に挿入されたコンテンツ。
  • ウェブフォント。

レイアウトのずれの原因を理解する

CLS に関する一般的な問題の解決策を検討する前に、CLS スコアとその変化の原因を把握することが重要です。

ラボツールの CLS とフィールドの CLS の比較

Chrome UX レポート(CrUX)で測定された CLS が、Chrome DevTools やその他のラボツールで測定された CLS と一致しないため、正しくないと思われることが多いようです。Lighthouse などのウェブ パフォーマンス ラボツールでは、通常はページを単純に読み込んでウェブ パフォーマンス指標を測定し、ガイダンスを提供するため、ページの CLS がすべて表示されないことがあります(ただし、Lighthouse ユーザーフローでは、デフォルトのページ読み込み監査を超えて測定できます)。

CrUX は Core Web Vitals プログラムの公式データセットです。そのため、CLS は、ラボツールで通常測定される最初のページ読み込み時だけでなく、ページの全期間にわたって測定されます。

レイアウト シフトは、最初にページをレンダリングするために必要なリソースがすべて取得されるため、ページの読み込み中によく発生しますが、初期読み込みの後にも発生することがあります。読み込み後のシフトの多くは、ユーザー インタラクションの結果として発生する可能性があります。そのため、そのインタラクションから 500 ミリ秒以内に発生する場合は、「想定」のシフトであるため、CLS スコアから除外されます。

ただし、ページをさらにスクロールして、遅延読み込みされたコンテンツが読み込まれ、その結果シフトが発生した場合など、ユーザーが予期しない読み込み後のシフトが、適格なインタラクションがない場所に含まれることがあります。読み込み後の CLS のその他の一般的な原因は、シングルページ アプリなどの遷移のインタラクションです。この場合、500 ミリ秒の猶予期間よりも時間がかかることがあります。

PageSpeed Insights では、[実際のユーザーが体験している内容を確認する] セクションに URL からのユーザー ペルセプション CLS と、[パフォーマンスの問題を診断する] セクションにラボベースの読み込み CLS の両方が表示されます。これらの値の差は、読み込み後の CLS が原因である可能性があります。

Lighthouse の CLS よりもかなり大きい実際のユーザー CLS をハイライト表示した URL レベルのデータが表示されている PageSpeed Insights のスクリーンショット
この例では、CrUX で測定される CLS は Lighthouse で測定される CLS よりもはるかに大きくなっています。

CLS の読み込みに関する問題を特定する

PageSpeed Insights の CrUX と Lighthouse の CLS スコアが概ね一致する場合、通常は Lighthouse によって検出された読み込み CLS の問題があることを示します。この場合、Lighthouse の 2 つの監査により、幅と高さが指定されていないために CLS が発生している画像に関する詳細情報を確認できます。また、ページの読み込み時にシフトしたすべての要素と、それらが CLS に与える影響も一覧表示されます。これらの監査は、CLS 監査でフィルタすると確認できます。

CLS の問題の特定と解決に役立つ詳細情報を提供する CLS 監査を示す Lighthouse のスクリーンショット
Lighthouse の詳細な CLS 診断。

DevTools の [パフォーマンス パネル] の [エクスペリエンス] セクションでも、レイアウトの変化がハイライト表示されます。Layout Shift レコードの [概要] ビューには、累積レイアウト シフト スコアと、影響を受ける領域を示す長方形のオーバーレイが表示されます。これは、読み込み CLS の問題を詳しく把握するのに特に役立ちます。この問題は、再読み込みのパフォーマンス プロファイルで簡単に再現できます。

[エクスペリエンス] セクションを開いたときに、Chrome DevTools のパフォーマンス パネルに表示されるレイアウト シフト レコード
[パフォーマンス] パネルで新しいトレースを記録すると、結果の [エクスペリエンス] セクションに、Layout Shift レコードを示す赤色のバーが追加されます。レコードをクリックすると、この画像の [移動元] や [移動先] などの詳細が表示され、影響を受ける要素をドリルダウンできます。

読み込み後の CLS の問題を特定する

CrUX と Lighthouse の CLS スコアが一致しない場合は、多くの場合、読み込み後の CLS を示しています。このような変化は、フィールドデータがないと追跡するのが難しい場合があります。フィールドデータの収集については、フィールドで CLS 要素を測定するをご覧ください。

Chrome 拡張機能「Web Vitals」を使用すると、ページの操作中にヘッドアップ ディスプレイまたはコンソールで CLS をモニタリングできます。コンソールでは、要素の移動に関する詳細情報を確認できます。

この拡張機能を使用する代わりに、コンソールに貼り付けた Performance Observer を使用してレイアウト シフトを記録しながら、ウェブページを閲覧することもできます。

シフト モニタリングをセットアップしたら、読み込み後の CLS の問題を再現してみます。CLS は、ユーザーがページをスクロールしているときに、遅延読み込みされたコンテンツが、そのコンテンツ用に予約されたスペースなしで完全に読み込まれたときに発生することがよくあります。ユーザーがポインタをコンテンツの上に置いたときにコンテンツが移動することも、読み込み後の CLS の一般的な原因です。これらのインタラクション中にコンテンツのシフトがあった場合、たとえ 500 ミリ秒以内に発生したとしても、想定外のアクティビティとしてカウントされます。

詳細については、レイアウト シフトをデバッグするをご覧ください。

CLS の一般的な原因を特定したら、Lighthouse のタイムスパン ユーザーフロー モードを使用して、レイアウト シフトによって一般的なユーザーフローが回帰しないようにすることもできます。

フィールドで CLS 要素を測定する

現場で CLS をモニタリングすることは、CLS が発生する状況を特定し、考えられる原因を絞り込むうえで非常に有用です。ほとんどのラボツールと同様に、フィールド ツールも変化した要素のみを測定しますが、通常はそれだけで原因を特定できるだけの十分な情報が得られます。CLS フィールド測定を使用して、修正の優先度が最も高い問題を特定することもできます。

web-vitals ライブラリには、この追加情報を収集できるアトリビューション関数があります。詳しくは、フィールドでパフォーマンスをデバッグするをご覧ください。他の RUM プロバイダも同様に、このデータの収集と表示を開始しています。

CLS の一般的な原因

CLS の原因を特定したら、問題の解決に取り掛かることができます。このセクションでは、CLS の一般的な原因と、それを回避するための方法について説明します。

ディメンションのない画像

画像要素と動画要素には、必ずサイズ属性 widthheight を含めます。または、CSS aspect-ratio などで必要なスペースを予約します。この方法により、画像の読み込み中、ブラウザはドキュメント内の適切な量のスペースを割り当てることができます。

幅と高さが指定されていない画像。
幅と高さが指定された画像。
画像にサイズを設定した後の累積レイアウト シフトへの影響の前後を示す Lighthouse レポート
画像サイズの設定が CLS に与える Lighthouse 6.0 の影響。

画像の width 属性と height 属性の履歴

ウェブの初期の頃、デベロッパーは <img> タグに width 属性と height 属性を追加して、ブラウザが画像の取得を開始する前にページに十分なスペースが割り当てられるようにしていました。これにより、再フローや再レイアウトを最小限に抑えることができます。

<img src="puppy.jpg" width="640" height="360" alt="Puppy with balloons">

この例の widthheight には単位が含まれていません。これらの「ピクセル」サイズにより、ブラウザはページのレイアウトで 640 x 360 の領域を予約します。画像は、実際のサイズがこのスペースと一致しているかどうかにかかわらず、このスペースに収まるように拡大されます。

レスポンシブ ウェブ デザインが導入されたとき、デベロッパーは widthheight を省略し始め、代わりに CSS を使用して画像のサイズを変更するようになりました。

img {
  width: 100%; /* or max-width: 100%; */
  height: auto;
}

ただし、画像サイズが指定されていないため、ブラウザがダウンロードを開始してサイズを特定するまで、画像にスペースを割り当てることはできません。画像が読み込まれると、画像のスペースを確保するためにテキストがページの下部に移動するため、ユーザー エクスペリエンスが混乱し、不満を感じる可能性があります。

ここでアスペクト比が重要になります。画像のアスペクト比は、幅と高さの比率です。通常、これはコロンで区切られた 2 つの数値(16:9 や 4:3 など)で表されます。x:y のアスペクト比の場合、画像の幅は x 単位、高さは y 単位です。

つまり、ディメンションの 1 つがわかっていれば、もう 1 つのディメンションを決定できます。アスペクト比 16:9 の場合:

  • puppy.jpg の高さが 360 ピクセルの場合、幅は 360 x(16 / 9)= 640 ピクセルになります。
  • puppy.jpg の幅が 640 ピクセルの場合、高さは 640 x(9 / 16)= 360 ピクセルになります。

画像のアスペクト比がわかれば、ブラウザは高さと関連領域に十分なスペースを計算して予約できます。

画像のサイズ設定に関する最新のベスト プラクティス

最新のブラウザでは、画像の width 属性と height 属性に基づいて画像のデフォルトのアスペクト比が設定されるため、これらの属性を画像に設定し、上記の CSS をスタイルシートに含めることで、レイアウトのずれを防ぐことができます。

<!-- set a 640:360 i.e a 16:9 aspect ratio -->
<img src="puppy.jpg" width="640" height="360" alt="Puppy with balloons">

すべてのブラウザでは、要素の既存の width 属性と height 属性に基づいてデフォルトのアスペクト比が追加されます。

これにより、画像が読み込まれる前に width 属性と height 属性に基づいてアスペクト比が計算されます。この情報は、レイアウト計算の開始時に提供されます。画像に特定の幅(width: 100% など)が指定されると、アスペクト比を使用して高さが計算されます。

この aspect-ratio 値は、デフォルトのユーザー エージェント スタイルシートではなく、HTML の処理時に主要なブラウザによって計算されるため(理由についてはこちらの投稿をご覧ください)、値の表示が少し異なります。たとえば、[要素] パネルの [スタイル] セクションには、次のように表示されます。

img[Attributes Style] {
  aspect-ratio: auto 640 / 360;
}

Safari も同様に、HTML 属性スタイルのソースを使用します。Firefox では、この計算された aspect-ratio は [インスペクタ] パネルにはまったく表示されませんが、レイアウトには使用されます。

上記のコード内の auto の部分は重要です。この部分により、画像のダウンロード後に画像のサイズがデフォルトのアスペクト比をオーバーライドします。画像のサイズが異なる場合でも、画像の読み込み後にレイアウトがシフトしますが、HTML が正しくない場合でも、画像のアスペクト比が利用可能になると、引き続きそのアスペクト比が使用されます。実際のアスペクト比がデフォルトとは異なる場合でも、寸法が指定されていない画像のデフォルトサイズ 0x0 よりもレイアウトのずれが少なくなります。

アスペクト比について詳しく学び、レスポンシブ画像についてさらに考えたい場合は、メディアのアスペクト比によるジャンクのないページ読み込みをご覧ください。

画像がコンテナ内にある場合は、CSS を使用して、コンテナの幅に合わせて画像のサイズを変更できます。画像の高さに固定値を使用しないように、height: auto; を設定しています。

img {
  height: auto;
  width: 100%;
}

レスポンシブ画像はどうですか?

レスポンシブ画像を使用する場合、srcset は、ブラウザが選択できるようにする画像と、各画像のサイズを定義します。<img> の width 属性と height 属性を設定できるようにするには、各画像で同じアスペクト比を使用する必要があります。

<img
  width="1000"
  height="1000"
  src="puppy-1000.jpg"
  srcset="puppy-1000.jpg 1000w, puppy-2000.jpg 2000w, puppy-3000.jpg 3000w"
  alt="Puppy with balloons"
/>

画像のアスペクト比は、アートディレクションによって変更することもできます。たとえば、狭いビューポートには画像の切り抜きショットを含め、パソコンでは画像全体を表示できます。

<picture>
  <source media="(max-width: 799px)" srcset="puppy-480w-cropped.jpg" />
  <source media="(min-width: 800px)" srcset="puppy-800w.jpg" />
  <img src="puppy-800w.jpg" alt="Puppy with balloons" />
</picture>

Chrome、Firefox、Safari で、特定の <picture> 要素内の <source> 要素に widthheight を設定できるようになりました。

<picture>
  <source media="(max-width: 799px)" srcset="puppy-480w-cropped.jpg" width="480" height="400" />
  <source media="(min-width: 800px)" srcset="puppy-800w.jpg" width="800" height="400" />
  <img src="puppy-800w.jpg" alt="Puppy with balloons" width="800" height="400" />
</picture>

広告、埋め込み、その他の遅延読み込みコンテンツ

レイアウト シフトを引き起こすコンテンツは画像だけではありません。広告、埋め込み、iframe などの動的に挿入されるコンテンツは、それらの後に表示されるコンテンツを下にずらす原因となり、CLS が増加する可能性があります。

ウェブ上のレイアウト シフトの原因として、広告が最も大きな要因の一つとなっています。多くの場合、広告ネットワークやパブリッシャーは動的な広告サイズに対応しています。広告サイズを大きくすると、クリック率が向上し、オークションで競合する広告が増えるため、パフォーマンスと収益が向上します。ただし、この方法では、表示中のコンテンツが広告によってページ下部に押しやられるため、最適なユーザー エクスペリエンスが得られなくなる可能性があります。

埋め込みウィジェットを使用すると、YouTube の動画、Google マップの地図、ソーシャル メディアの投稿など、ポータブルなウェブ コンテンツをページに含めることができます。しかし、こうしたウィジェットは多くの場合、読み込み前に内容のサイズを認識していません。そのため、埋め込みを提供するプラットフォームでは、ウィジェット用のスペースが常に予約されているわけではなく、最終的に読み込まれたときにレイアウトがずれる原因となります。

これらに対処するための手法はすべて似ています。主な違いは、挿入されるコンテンツをどの程度制御できるかです。広告パートナーなどのサードパーティによって埋め込まれたコンテンツの場合、埋め込まれるコンテンツの正確なサイズがわからない場合や、埋め込みコンテンツ内で発生するレイアウトのずれを制御できない場合があります。

遅れて読み込まれるコンテンツ用のスペースを予約する

遅延読み込みコンテンツをコンテンツフローに配置する場合は、初期レイアウトでそのコンテンツのスペースを予約することで、レイアウトのずれを回避できます。

1 つの方法は、min-height CSS ルールを追加してスペースを予約することです。広告などのレスポンシブ コンテンツの場合は、ブラウザが指定されたサイズの画像に自動的に使用する方法と同様に、aspect-ratio CSS プロパティを使用します。

3 つのモバイル デバイス。1 台目のデバイスにはテキスト コンテンツのみが表示され、2 台目のデバイスでは下方にずれています。3 台目のデバイスのようにプレースホルダでスペースを予約すると、ずれは防止できます
広告用のスペースを確保することでレイアウト シフトを防止できる

メディアクエリを使用して、フォーム ファクタ間で広告やプレースホルダのサイズの微妙な違いを考慮する必要がある場合があります。

広告など、高さが固定されていないコンテンツの場合、レイアウト シフトを完全に排除するために必要なスペースを正確に確保できないことがあります。小さい広告が配信される場合は、レイアウト シフトを避けるため、大きいコンテナのスタイルを設定するか、過去のデータに基づいて広告スロットに最も適したサイズを選択します。この方法の欠点は、ページの空白スペースが増えることです。

代わりに、初期サイズを使用される最小サイズに設定し、サイズの大きいコンテンツに対してある程度のずれを許容することもできます。前述のように min-height を使用すると、空の要素のデフォルトサイズ 0 px と比較して、レイアウト シフトの影響を軽減しながら、必要に応じて親要素を拡大できます。

広告が返されなかった場合などに、プレースホルダを表示して、予約済みスペースが折りたたまれることを避けてください。要素用に確保されたスペースを削除すると、コンテンツを挿入した場合と同様に CLS が増加する可能性があります。

遅れて読み込まれるコンテンツをビューポートの下部に配置する

ビューポートの上部に近い位置に動的に挿入されたコンテンツは、ビューポートの下部に挿入されたコンテンツよりもレイアウトのずれが大きくなることが一般的です。ただし、ビューポート内の任意の場所にコンテンツを挿入すると、多少のずれが生じます。挿入されるコンテンツのスペースを予約できない場合は、CLS への影響を軽減するために、ページの後半に配置することをおすすめします。

ユーザーの操作なしで新しいコンテンツを挿入しない

サイトの読み込み時にビューポートの上部または下部に UI がポップインし、レイアウトがずれるという問題が発生したことがあると思います。広告と同様に、これは多くの場合、ページの残りのコンテンツを移動するバナーやフォームで発生します。

スペースを予約していない動的コンテンツ。

このようなタイプの UI アフォーダンスを表示する必要がある場合は、読み込み時にページのコンテンツが予期せず移動しないように、ビューポートに十分なスペースを事前に予約しておきます(プレースホルダ UI やスケルトン UI を使用するなど)。または、適切なコンテンツをオーバーレイすることで、要素がドキュメント フローの一部にならないようにします。このようなコンポーネントに関する推奨事項については、Cookie の通知に関するベスト プラクティスの投稿をご覧ください。

コンテンツを動的に追加することは、ユーザー エクスペリエンスの重要な要素である場合もあります。たとえば、商品アイテムのリストに商品を追加する場合や、ライブフィード コンテンツを更新する場合などです。このような場合に予期しないレイアウトのずれを回避するには、いくつかの方法があります。

  • 固定サイズのコンテナ内で古いコンテンツを新しいコンテンツに置き換えるか、カルーセルを使用して移行後に古いコンテンツを削除します。新しいコンテンツの読み込み中に誤ってクリックやタップしないように、移行が完了するまでリンクとコントロールを無効にしてください。
  • ユーザーが新しいコンテンツの読み込みを開始できるようにします(「もっと読み込む」ボタンや「更新」ボタンなど)。これにより、ユーザーはコンテンツの切り替えに驚かされることはありません。ユーザーが操作を行う前にコンテンツをプリフェッチして、すぐに表示されるようにすることをおすすめします。なお、ユーザー入力から500 ミリ秒以内に発生したレイアウト シフトは CLS の対象になりません。
  • コンテンツを画面外にシームレスに読み込み、コンテンツが利用可能であることをユーザーに通知するオーバーレイを表示します(「上にスクロール」ボタンなど)。
Twitter と Chloé のウェブサイトから予期しないレイアウト シフトを発生させずに動的なコンテンツを読み込む例
予期しないレイアウト シフトを発生させない動的なコンテンツの読み込みの例。左: Twitter でライブフィード コンテンツが読み込まれている様子。右: Chloé のウェブサイトの「もっと見る」の例。YNAP チームがコンテンツの読み込み時の CLS を最適化した方法をご覧ください。

アニメーション

CSS プロパティの値を変更すると、ブラウザがそれらの変更に対応することが必要になる場合があります。box-shadowbox-sizing などの値は、再レイアウト、ペイント、コンポジットをトリガーします。top プロパティと left プロパティを変更すると、移動する要素が独自のレイヤにある場合でも、レイアウトがずれます。これらのプロパティを使用してアニメーション化しないでください。

他の CSS プロパティは、再レイアウトをトリガーせずに変更できます。たとえば、transform アニメーションを使用して要素を移動、拡大縮小、回転、スキューするなどです。

translate を使用した合成アニメーションは他の要素に影響を与えないため、CLS の対象にはなりません。合成されていないアニメーションでも、再レイアウトは行われません。レイアウト シフトをトリガーする CSS プロパティについて詳しくは、高パフォーマンスのアニメーションをご覧ください。

ウェブフォント

ウェブフォントのダウンロードとレンダリングは通常、ウェブフォントのダウンロード前に次の 2 つの方法のいずれかで処理されます。

  • 代替フォントがウェブフォントに置き換えられ、スタイルなしテキスト(FOUT)の Flash が発生します。
  • 「非表示」のテキストは、ウェブ フォントが利用可能になり、そのテキストが表示されるまで、代替フォントを使用して表示されます(FOIT(非表示テキストのフラッシュ))。

どちらの方法でもレイアウト シフトが発生する可能性があります。テキストが非表示の場合でも、フォールバック フォントを使用してレイアウトされるため、Web フォントが読み込まれると、テキスト ブロックとその周囲のコンテンツは、表示されているフォントの場合と同様に移動します。

テキストのずれを最小限に抑えるには、次のツールを使用します。

  • font-display: optional は、ウェブフォントが初期レイアウトの時点までで利用可能な場合にのみ使用されるため、再レイアウトを回避できます。
  • 適切な代替フォントが使用されていることを確認します。たとえば、font-family: "Google Sans", sans-serif; を使用すると、"Google Sans" の読み込み中はブラウザの sans-serif 代替フォントが使用されます。font-family: "Google Sans" のみを使用して代替フォントを指定しない場合、デフォルトのフォントが使用されます。Chrome では「Times」というセリフフォントが使用されます。これは、デフォルトの sans-serif フォントよりも適合性が低いフォントです。
  • フォントのフォールバック機能の改善の投稿で詳しく説明されているように、新しい size-adjustascent-overridedescent-overrideline-gap-override API を使用して、フォールバック フォントとウェブフォント間のサイズの差異を最小限に抑えます。
  • Font Loading API を使用すると、必要なフォントを取得する時間を短縮できます。
  • <link rel=preload> を使用して、重要なウェブフォントをできるだけ早く読み込みます。プリロードされたフォントは、ファースト ペイントの条件を満たす可能性が高くなります。この場合、レイアウトのずれはありません。

その他のフォントに関するおすすめの方法については、フォントに関するおすすめの方法をご覧ください。

ページが bfcache の対象となるようにすることで CLS を削減する

CLS スコアを低く抑える効果的な方法として、ウェブページが前後キャッシュ(bfcache)の対象となるようにすることが挙げられます。

bfcache では、ページを離れた後、ページをブラウザのメモリに短時間保持するので、元のページに戻ったときに元のページが復元されます。つまり、完全に読み込まれたページはすぐに使用可能になり、前述の理由により読み込み中に発生する可能性のあるシフトは発生しません。

この場合も、最初のページの読み込み時にレイアウト シフトが発生している可能性がありますが、ユーザーがページに戻ってきたときに同じレイアウト シフトが繰り返し表示されないということです。初期読み込み時であっても常にシフトを避けるようにする必要がありますが、完全に解決するのが難しい場合は、少なくとも bfcache ナビゲーションで移動しないようにすることで、影響を軽減できます。

前後に移動するナビゲーションは、多くのサイトで一般的です。たとえば、コンテンツ ページ、カテゴリページ、検索結果に戻る。

この機能が Chrome にロールアウトされたとき、CLS が大幅に改善されました。

bfcache はすべてのブラウザでデフォルトで使用されますが、さまざまな理由により、一部のサイトは bfcache の対象外となります。bfcache の使用を妨げる問題をテストして特定する方法の詳細については、bfcache ガイドをご覧ください。この機能を最大限に活用して、サイトの全体的な CLS スコアを向上させてください。

まとめ

このガイドの前半で説明したように、CLS を特定して改善するための手法はいくつかあります。Core Web Vitals には許容範囲が組み込まれているため、CLS を完全に排除できない場合でも、これらの手法のいくつかを使用すると、影響を軽減できます。これにより、上限内に収まり、ウェブサイトのユーザーにとっての利便性が向上します。