Cumulative Layout Shift の最適化

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

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

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

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

CLS の値が 0.1 未満で、値が 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 は、Web Vitals プログラムの公式データセットです。そのため、CLS は、ラボツールで通常測定される最初のページ読み込み時だけでなく、ページ全体を通じて測定されます。

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

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

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

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

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

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

CLS 監査を示す Lighthouse のスクリーンショット。CLS の問題の特定と対処に役立つ詳細な情報を確認できる
Lighthouse の詳細な CLS 診断。

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

Chrome DevTools のパフォーマンス パネルに [エクスペリエンス] セクションを開くと、Layout Shift レコードが表示される
[パフォーマンス] パネルで新しいトレースを記録すると、結果の [エクスペリエンス] セクションに、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 などを使用して必要なスペースを予約します。このアプローチにより、画像の読み込み中にブラウザがドキュメントに適切な量のスペースを割り当てることができます。

<ph type="x-smartling-placeholder">
幅と高さが指定されていない画像。
<ph type="x-smartling-placeholder">
幅と高さが指定された画像。
画像にサイズを設定した後の累積レイアウト シフトへの影響の前後を示す Lighthouse レポート
Lighthouse 6.0 で画像のサイズ設定が CLS に及ぼす影響

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

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

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

この例の widthheight には単位が含まれていません。この「ピクセル」はブラウザがページのレイアウト内に 640×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 が [Inspector] パネルには一切表示されませんが、レイアウトに使用されます。

上記のコード内の 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 で widthheight の設定がサポートされるようになりました 特定の <picture> 要素内の <source> 要素:

<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 ピクセルと比較して、レイアウト シフトの影響を抑えながら、必要に応じて親要素を拡大できます。

広告が返されなかった場合など、プレースホルダを表示して、予約済みスペースが折りたたまれることを避けてください。要素のために確保しておいたスペースを削除すると、コンテンツの挿入と同じくらい 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(非表示テキストの点滅))。

どちらの方法でもレイアウト シフトが発生する可能性があります。テキストが非表示の場合でも代替フォントでレイアウトされるため、ウェブフォントが読み込まれると、テキスト ブロックと周囲のコンテンツは、表示フォントの場合と同じように移動します。

テキストのシフトを最小限に抑えるには、次のツールが役立ちます。

  • 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> を使用して、重要なウェブフォントをできるだけ早く読み込みます。プリロードされたフォントは、First Paint を満たす可能性が高くなります。この場合、レイアウトは移動しません。

フォントに関するその他のベスト プラクティスについては、フォントに関するおすすめの方法をご覧ください。

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

CLS スコアを低く保つための非常に効果的な手法は、ウェブページが前後キャッシュ(bfcache)の対象となるようにすることです。

bfcache は、ページから移動した後もブラウザのメモリにページを短時間保持するため、ページに戻ったときに、そのページは離れたときとまったく同じ状態で復元されます。つまり、前述したような理由で読み込み時に見られるような移動を発生させることなく、完全に読み込まれたページをすぐに利用できます。

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

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

この機能を Chrome に展開したところ、CLS が著しく改善されました。

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

まとめ

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