Cumulative Layout Shift の最適化

Cumulative Layout Shift(CLS)は、Core Web Vitals の 3 つの指標のうちの一つです。ビューポート内の表示コンテンツの量と影響を受ける要素が移動した距離を組み合わせて、コンテンツの不安定性を測定します。

レイアウト シフトはユーザーの気を散らすことがあります。たとえば、記事を読み始めたところ、突然ページ内でさまざまな要素が移動し、心が躍り、もう一度場所を探す必要があったとします。これは、ニュースを読んだり、[検索] ボタンや [カートに追加] ボタンをクリックしようとする場合など、ウェブ上で非常に一般的です。そのようなエクスペリエンスは、視覚的に不快でフラストレーションを感じます。多くの場合、別の要素が突然ページに追加されたかサイズ変更されたために、表示可能な要素が強制的に移動されました。

優れたユーザー エクスペリエンスを提供するには、サイトのページ訪問の 75% 以上で CLS が 0.1 以下である必要があります。

良好な CLS 値は 0.1 以下、不良な値は 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 は、Web Vitals プログラムの公式データセットです。ラボツールで通常測定する最初のページ読み込み時だけでなく、ページのライフサイクル全体を通して CLS を測定します。

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

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

PageSpeed Insights では、[実際のユーザー エクスペリエンスを確認する] セクションに URL からユーザーが認識した CLS が表示され、[パフォーマンスの問題を診断する] セクションにラボベースの負荷 CLS の両方が表示されます。これらの値の差異は、読み込み後の CLS の結果であると考えられます。

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

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

PageSpeed Insights で CrUX と Lighthouse の CLS スコアが類似している場合、通常は、Lighthouse が CLS の読み込みに関する問題を検出したことを意味します。この場合、Lighthouse では 2 つの監査を実施して詳細情報を確認できます。1 つは、幅と高さの欠落により CLS を発生させている画像、もう 1 つはページの読み込み中に CLS の寄与とともにシフトしたすべての要素に関する監査です。これらの監査を表示するには、次の図のようにフィルタします。

CLS の監査結果を示す Lighthouse のスクリーンショット。CLS の問題の特定と対処に役立つ詳細情報が提供されています。
Lighthouse による詳細な CLS 診断。

DevTools の [パフォーマンス] パネルでも、[エクスペリエンス] セクションのレイアウト シフトがハイライト表示されます。Layout Shift レコードの [Summary] ビューには、CLS スコアと、影響を受けるリージョンを示す長方形のオーバーレイが表示されます。これらは、再読み込みのパフォーマンス プロファイルでユーザー エクスペリエンスを再現できるため、読み込み CLS の問題の特定に特に役立ちます。

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

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

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

Web Vitals の Chrome 拡張機能を使用すると、ヘッドアップ ディスプレイで、またはコンソールで、シフトした要素の詳細とともに、ページの操作中に CLS をモニタリングできます。

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

シフト モニタリングを設定したら、読み込み後の CLS の問題を再現できます。CLS は、ユーザーがページをスクロールしている間、つまり遅延読み込みコンテンツが、専用のスペースを確保せずに完全に読み込まれるときによく発生します。ユーザーがポインタの上にポインタを置いたときのコンテンツ シフトも、読み込み後の CLS の一般的な原因です。これらの操作のいずれかでコンテンツが変化すると、500 ミリ秒以内に発生したとしても予期しないものとしてカウントされます。

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

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

現場の CLS 要素を測定する

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

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

CLS の一般的な原因

このセクションでは、CLS の一般的な理由と回避方法について説明します。

サイズが指定されていない画像

画像要素と動画要素には、必ず widthheight のサイズ属性を指定するか、CSS aspect-ratio を使用して必要なスペースを確保します。これにより、画像の読み込み中にブラウザがドキュメントに適切な量のスペースを割り当てることができます。

幅と高さが指定されていない画像。

幅と高さが指定されている画像。

画像にディメンションを設定した後の Cumulative Layout Shift の使用前後の影響を示す Lighthouse レポート
画像のサイズの設定に対する Lighthouse 6.0 の CLS への影響

widthheightaspect-ratio

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

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

この例の widthheight には単位がありません。この「ピクセル」サイズによって、ブラウザが 640x360 の領域を予約することになります。実際の寸法が一致しているかどうかにかかわらず、このスペースに合わせて画像が拡大されます。

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

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

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

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

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

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

ブラウザは、要素の既存の width 属性と height 属性に基づいてデフォルトのアスペクト比を追加します。これにより、レイアウトの計算開始時に画像用に予約するスペースを決定できます。

主要なブラウザでは、HTML の処理時にデフォルトのアスペクト比が計算されるため、ブラウザによって表示方法が若干異なります。(その理由については、幅と高さの表示に関するヒントをご覧ください)。

たとえば、Chrome の [要素] パネルの [スタイル] セクションには、次のようなアスペクト比が表示されます。

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> の幅と高さの属性を設定できるようにするには、各画像に同じアスペクト比を使用します。

<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 マップの地図、ソーシャル メディアの投稿など、ポータブルなウェブ コンテンツをページに組み込むことができます。しかし多くの場合、こうしたウィジェットは読み込み前にコンテンツのサイズを認識しません。そのため、埋め込みを提供するプラットフォームでは、必ずしもウィジェット用のスペースが確保されるわけではありません。そのため、最終的に読み込まれるときにレイアウトが移動します。

対処方法はどれもほぼ同じです。主な違いは、挿入されたコンテンツをどの程度制御できるかにあります。多くの場合、広告パートナーなどの第三者からは、挿入されたコンテンツに関する有用な情報や、これらの埋め込みに起因するレイアウト シフトを制御できません。

遅延読み込みコンテンツ用のスペースを確保する

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

これは、スペースを予約するために min-height スタイルを追加することや、広告などのレスポンシブ コンテンツの場合は、ブラウザで画像を自動的に使用する場合と同様の方法で、新しい aspect-ratio CSS プロパティを使用するだけで簡単に行えます。

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

メディアクエリでは、フォーム ファクタ間で広告やプレースホルダのサイズのわずかな違いを考慮する必要があります。

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

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

広告が返されない場合などは、プレースホルダを表示して、予約済みのスペースが折りたたまれないようにしてください。要素用に確保されたスペースを削除すると、コンテンツの挿入と同じ CLS が発生する可能性があります。

読み込みが遅いコンテンツをビューポートの下方に配置する

動的に挿入されたコンテンツがビューポートの上部に近いほど、通常はビューポートの下部に挿入されたコンテンツよりもレイアウト シフトが大きくなる。ただし、ビューポートの任意の場所にコンテンツを挿入しても、ある程度の移動が発生します。挿入されたコンテンツ用のスペースを予約できない場合は、影響を軽減するために、ページの後半に配置することをおすすめします。

オーバーレイ バナー コンテンツ

ページ上にバナーやフォームが予期せず表示されることも、予期しないレイアウト シフトの原因となります。

スペースが予約されていない動的コンテンツ。

このようなコンテンツ用のスペースを確保できない場合は、代わりに既存のコンテンツにオーバーレイして、ドキュメント フローから除外できます。この方法を使用するタイミングについては、Cookie の通知に関するベスト プラクティスをご覧ください。

ユーザー操作によって想定されるレイアウト シフトがトリガーされるようにする

アイテムのリストにさらに商品を読み込む場合や、ライブフィード コンテンツを更新する場合など、コンテンツを動的に追加することがユーザー エクスペリエンスの重要な部分になることもあります。そのような場合に予期しないレイアウト シフトを回避するには、いくつかの方法があります。

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

アニメーション

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

他の CSS プロパティは、再レイアウトをトリガーせずに変更できます。たとえば、transform アニメーションを使用した要素の平行移動、スケーリング、回転、偏りなどです。

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

ウェブフォント

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

  • 代替フォントは、Flash of Unstyled Text(FOUT)を使用してウェブフォントと入れ替えられます。
  • 「非表示」のテキストは、ウェブフォントが利用可能になり、テキストが表示されるようになるまで、Flash of Invisible Text(FOIT)を使用して表示されます。

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

次のツールを使用すると、このテキストのシフトを最小限に抑えることができます。

  • font-display: optional は、初期レイアウト時までにウェブフォントが使用可能になった場合にのみ、ウェブフォントを使用します。
  • ウェブフォントに似た代替フォントを使用します。たとえば、font-family: "Google Sans", sans-serif; を使用すると、"Google Sans" の読み込み中にブラウザは sans-serif 代替フォントを使用します。代替フォントを指定しない(font-family: "Google Sans" のみを使用)と、Chrome はデフォルトの Serif フォントを使用しますが、この方には適していません。
  • 新しい size-adjust API、ascent-override API、descent-override API、line-gap-override API を使用して、代替フォントとウェブフォントのサイズの差を最小限に抑えます。詳しくは、フォント フォールバックの改善をご覧ください。
  • Font Loading API を使用すると、フォントの読み込み時間を短縮できます。
  • <link rel=preload> を使用して、重要なウェブフォントをできるだけ早く読み込みます。プリロード済みフォントは、First Paint の準備ができる可能性が高く、レイアウト シフトは発生しません。

詳しくは、フォントに関するおすすめの方法をご覧ください。

ページを bfcache の対象にする

CLS スコアを低く抑える最も効果的な方法は、ウェブページがバックフォワード キャッシュ(bfcache)の対象になるようにすることです。

bfcache は、ページから移動した後も少しの間、ブラウザのメモリにページを保持します。そのため、ページに戻ったときに、元のページとまったく同じページが復元されます。つまり、ページの読み込み中にシフトが生じることなく、完全に読み込まれたページが即座に利用可能になります。

これは、最初のページ読み込みでレイアウト シフトが発生することを意味しますが、ユーザーは同じレイアウト シフトが繰り返し表示されることを回避できます。これにより、他の方法で解決できないレイアウト シフトの影響を軽減できます。

「戻る」ナビゲーションと「進む」ナビゲーションは、目次ページ、カテゴリページ、検索結果など、多くのサイトでよく見られます。

bfcache はすべてのブラウザでデフォルトで使用されますが、さまざまな理由により使用できないサイトもあります。bfcache の使用を妨げる問題をテストして特定する方法については、bfcache に関する記事をご覧ください。