Cumulative Layout Shift の最適化

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

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

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

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

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

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

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

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

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

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

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 単位です。

つまり、一方の寸法がわかれば、もう一方の寸法も決定できます。アスペクト比 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 の処理時に主要なブラウザによって計算されるため(理由についてはこちらの投稿をご覧ください)、値の表示が少し異なります。たとえば、Chrome では [Elements] パネルの [Styles] セクションに次のように表示されます。

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 を使用するなど)、読み込み時にページ内のコンテンツが突然移動しないようにします。または、コンテンツをオーバーレイして、その要素がドキュメントの流れの一部ではないことを確認します。このようなコンポーネントに関するその他の推奨事項については、Cookie に関する通知に関するベスト プラクティスの投稿をご覧ください。

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

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

アニメーション

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

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

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

ウェブフォント

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

  • 代替フォントがウェブフォントと入れ替わり、Flash of Unstyled Text(FOUT)が発生します。
  • 代替フォントを使用して「見えない」テキストが表示され、Web フォントが利用可能になりテキストが可視化されるまでこの状態が続く(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 を完全に排除できない場合でも、これらの手法のいくつかを使用すると、影響を軽減できます。これにより、上限内に収まり、ウェブサイトのユーザーにとっての利便性が向上します。