Cumulative Layout Shift(CLS)

対応ブラウザ

  • 77
  • 79
  • x
  • x

ソース

レイアウトが予期せず移動すると、テキストが急に進んだ場合に読む際に別の位置に落ちたり、間違ったリンクやボタンをクリックさせたりするなど、さまざまな形でユーザー エクスペリエンスが損なわれる可能性があります。場合によっては、これによって深刻な被害が生じることがあります。

レイアウトが突然変わると、ユーザーはキャンセルする予定の大量注文を確定することになります。

ページ コンテンツの予期しない移動は、通常、リソースが非同期で読み込まれたり、DOM 要素が既存のコンテンツよりも先にページに動的に追加された場合に発生します。レイアウトがずれる原因としては、サイズが不明な画像や動画、元の代替サイズよりも大きくまたは小さく表示されるフォント、動的にサイズ変更されるサードパーティの広告やウィジェットなどがあります。

開発中のサイトの動作とユーザー エクスペリエンスの違いは、この問題をさらに悪化させます。次に例を示します。

  • パーソナライズド コンテンツやサードパーティのコンテンツの動作は、多くの場合、開発時と本番環境で異なります。
  • 多くの場合、テスト画像はすでにデベロッパーのブラウザ キャッシュにありますが、エンドユーザーにとっての読み込みには時間がかかります。
  • ローカルで実行される API 呼び出しはたいてい非常に速いため、開発における目立たない遅延が本番環境でかなり大きくなる可能性があります。

Cumulative Layout Shift(CLS)指標を使用すると、実際のユーザーでこの問題が発生する頻度を測定することで、この問題に対処できます。

CLS とは

CLS は、ページのライフサイクル全体を通じて発生する予期しないレイアウト シフトごとに、レイアウト シフト スコアのバーストの最大値を測定します。

レイアウト シフトは、可視要素の位置がレンダリングされたフレームから次のフレームに変更されるたびに発生します。(個々のレイアウト シフトスコアの計算方法については、このガイドの後半で説明します)。

レイアウト シフトのバースト(セッション ウィンドウ)とは、1 つ以上の個別のレイアウト シフトが、各シフトの間隔が 1 秒未満で、ウィンドウ時間全体で最大 5 秒で、連続して発生することです。

最大のバーストは、そのウィンドウ内のすべてのレイアウト シフトの最大累積スコアを持つセッション ウィンドウです。

セッション ウィンドウの例。青いバーは個々のレイアウト シフトのスコアを表します。

良い CLS スコアとは何ですか?

優れたユーザー エクスペリエンスを提供するには、サイトの CLS スコアを 0.1 以下にする必要があります。ほとんどのユーザーでこの目標値を達成するには、ページ読み込みの 75 パーセンタイルをモバイル デバイスとデスクトップ デバイスでセグメント化して測定するしきい値として適しています。

良好な CLS 値は 0.1 以下、不良な値は 0.25 より大きく、その間はすべて改善が必要
適切な CLS 値は 0.1 以下です。低い値は 0.25 より大きくなります。

この推奨事項の背景にある調査と手法について詳しくは、Core Web Vitals 指標のしきい値の定義をご覧ください。

レイアウト シフトの詳細

レイアウト シフトは Layout Instability API によって定義されます。この API は、ビューポート内に表示される要素が開始位置(たとえば、デフォルトの書き込みモードでの上と左の位置)を 2 フレーム間で変更するたびに layout-shift エントリを報告します。このような要素は不安定要素とみなされます。

レイアウト シフトは、既存の要素の開始位置が変更された場合にのみ発生します。新しい要素が DOM に追加された場合や、既存の要素のサイズが変更された場合は、他の可視要素の開始位置が変更されない限り、レイアウトの移動としてはカウントされません。

レイアウト シフトのスコア

ブラウザは、レイアウト シフト スコアを計算するために、ビューポートのサイズと、レンダリングされた 2 つのフレーム間のビューポート内の不安定な要素の動きを調べます。レイアウト シフト スコアは、その動きを計測する 2 つの測定値の積です。「影響の割合」と「距離の割合」(どちらも下記で定義)です。

layout shift score = impact fraction * distance fraction

影響の割合

影響の割合は、不安定な要素が 2 つのフレーム間のビューポート領域に及ぼす影響を測定します。

特定のフレームに対する影響の割合は、そのフレームと前のフレームの不安定要素すべての表示領域を、ビューポートの合計領域に占める割合で表します。

不安定な要素が 1 つある影響の割合の例
要素の位置が変更された場合、その前の位置と現在の位置の両方が影響の割合に影響します。

上の画像では、1 フレームでビューポートの半分を占める要素があります。次のフレームで、要素はビューポートの高さの 25% だけ下に移動します。赤色の点線の長方形は、両方のフレームの要素の表示領域が合わさっていることを示します。この例では、ビューポート全体の 75% を占めるため、「影響の割合」0.75 となります。

距離分数

レイアウト シフトのスコア式のもう 1 つの部分は、不安定な要素がビューポートに対して移動した距離を測定します。距離の割合は、不安定な要素がフレーム内で移動した水平方向または垂直方向の最大距離を、ビューポートの最大寸法(幅または高さのいずれか大きい方)で割ったものです。

不安定な要素が 1 つある距離分数の例
距離の割合は、要素がビューポート全体にわたって移動した距離を測定します。

前の例では、ビューポートの最大寸法は高さであり、不安定な要素がビューポートの高さの 25% 移動したため、距離の割合は 0.25 になります。

したがって、この例では、影響の割合0.75、距離の割合0.25 であるため、レイアウト シフトのスコア0.75 * 0.25 = 0.1875 になります。

次の例は、既存の要素にコンテンツを追加すると、レイアウト シフト スコアにどのように影響するかを示しています。

複数の安定版要素と不安定要素があるレイアウト シフトの例
灰色のボックスの下部にボタンを追加すると、緑色のボックスが下に押し下げられ、部分的にビューポートから外れます。

この例では、グレーのボックスのサイズは変化しますが、開始位置は変更されないため、不安定な要素ではありません。

「Click Me!」ボタンは以前は DOM に存在していなかったので、開始位置も変わりません。

ただし、緑色のボックスの開始位置は変化しますが、ビューポートから部分的に移動されているため、非表示領域は影響の割合を計算する際に考慮されません。両方のフレームの緑色のボックスの表示領域(赤い点線の長方形で表示)の合計は、最初のフレームの緑色のボックスの面積(ビューポートの 50%)と同じです。影響の割合0.5 です。

距離の割合は、紫色の矢印で表示されます。緑色のボックスはビューポートの約 14% 下に移動しているため、距離の割合0.14 です。

レイアウト シフトのスコアは 0.5 x 0.14 = 0.07 です。

次の例は、複数の不安定な要素がページのレイアウト シフト スコアにどのように影響するかを示しています。

安定した要素と不安定な要素とビューポートのクリッピングを使用したレイアウト シフトの例
この並べ替えられたリストにさらに名前が表示されると、既存の名前がアルファベット順に移動します。

上の画像の最初のフレームには、動物に対する API リクエストの 4 つの結果がアルファベット順に表示されます。2 番目のフレームでは、並べ替えられたリストに結果が追加されます。

リスト内の最初のアイテム(「Cat」)は、フレーム間で開始位置を変更しないので安定しています。同様に、リストに追加される新しいアイテムも DOM 内には存在していないため、開始位置も変わりません。しかし、「犬」、「馬」、「ゼブラ」というラベルの付いたアイテムはすべて開始位置がずらされるため、要素が不安定になります。

ここでも、赤い点線の長方形は、前後の 3 つの不安定な要素を合わせた部分を表しています。この例では、ビューポートの領域の約 60%(0.60影響の割合)です。

矢印は、不安定な要素が開始位置から移動した距離を表します。青い矢印で表される「ゼブラ」要素が、ビューポートの高さの約 30% 移動した場合。これにより、この例の距離の割合は 0.3 になります。

レイアウト シフトのスコアは 0.60 x 0.3 = 0.18 です。

想定されるレイアウト シフトと予期しないレイアウト シフト

すべてのレイアウト シフトが悪いわけではありません。実際、多くの動的ウェブ アプリケーションでは、ページ上の要素の開始位置が頻繁に変更されます。レイアウト シフトは、ユーザーが予期していない場合にのみ適切ではありません。

ユーザーが開始するレイアウト シフト

ユーザー インタラクション(リンクのクリックやタップ、ボタンの押下、検索ボックスへの入力など)に反応して発生するレイアウト シフトは、関係がユーザーに明確になるほどインタラクションに近い位置で発生する限り、通常は問題ありません。

たとえば、ユーザーの操作によってネットワーク リクエストがトリガーされ、完了に時間がかかる場合は、すぐにスペースを作成して読み込みインジケーターを表示することで、リクエスト完了時に不愉快なレイアウト シフトが発生しないようにすることをおすすめします。ユーザーが、何かが読み込まれていることに気づかない場合や、リソースの準備が整うタイミングがわからない場合、待っている間に別の何かをクリックしようとします。

ユーザー入力から 500 ミリ秒以内に発生するレイアウト シフトには hadRecentInput フラグが設定され、計算から除外できます。

アニメーションと遷移

アニメーションと遷移を効果的に使用すると、ユーザーを驚かせることなくページのコンテンツを更新できます。ページ上のコンテンツが突然、予期せず移動すると、ほとんどの場合、ユーザー エクスペリエンスが低下します。しかし、ある位置から次の位置に徐々に自然に移動するコンテンツは、多くの場合、ユーザーが何が起こっているかをよりよく理解し、状態が変化する間にガイドするのに役立ちます。

prefers-reduced-motion のブラウザ設定を尊重してください。アニメーションが原因でサイト訪問者によっては、悪影響や注意力の問題が発生することがあります。

CSS の transform プロパティを使用すると、レイアウト シフトをトリガーせずに要素をアニメーション化できます。

  • height プロパティと width プロパティを変更する代わりに、transform: scale() を使用します。
  • 要素を移動するには、toprightbottomleft プロパティを変更せず、代わりに transform: translate() を使用します。

CLS の測定方法

CLS はラボまたは現場で測定でき、以下のツールで利用できます。

フィールド ツール

ラボ用ツール

JavaScript でレイアウト シフトを測定する

JavaScript でレイアウト シフトを測定するには、Layout Instability API を使用します。

次の例は、コンソールに layout-shift エントリを記録する PerformanceObserver の作成方法を示しています。

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('Layout shift:', entry);
  }
}).observe({type: 'layout-shift', buffered: true});

JavaScript で CLS を測定する

JavaScript で CLS を測定するには、このような想定外の layout-shift エントリをセッションごとにグループ化し、セッションの最大値を算出する必要があります。CLS の計算方法のリファレンス実装については、web vitals JavaScript ライブラリのソースコードをご覧ください。

ほとんどの場合、ページがアンロードされたときの現在の CLS 値がそのページの最終的な CLS 値ですが、次のセクションで説明するように、いくつかの重要な例外があります。web vitals JavaScript ライブラリは、ウェブ API の制限内で、可能な限りこれらを考慮します。

指標と API の違い

  • ページがバックグラウンドで読み込まれた場合、またはブラウザがコンテンツを描画する前にバックグラウンドに設定されていた場合は、CLS 値をレポートしません。
  • ページがバックフォワード キャッシュから復元された場合、CLS 値は 0 にリセットされる必要があります。これは、ユーザーが個別のページ訪問として見なすためです。
  • この API は iframe 内で発生する移動に対して layout-shift エントリをレポートしませんが、指標はページのユーザー エクスペリエンスの一部であるため、レポートします。これは、CrUX と RUM の違いとして表される場合があります。CLS を適切に測定するには、これらを考慮する必要があります。サブフレームは API を使用して、集計のためにその layout-shift エントリを親フレームに報告できます。

CLS では、これらの例外に加えて、ページの存続期間全体を測定するため、より複雑になります。

  • ユーザーは、非常に長い時間(数日、数週間、数か月)タブを開いたままにしている場合があります。実際、ユーザーがタブを閉じたりすることはありません。
  • モバイル オペレーティング システムでは、ブラウザは通常、バックグラウンド タブのページ アンロード コールバックを実行しないため、「最終」値の報告が困難です。

このようなケースに対処するには、ページがアンロードされたときだけでなく、ページがバックグラウンドになるたびに CLS を報告する必要があります(visibilitychange イベントで両方のシナリオに対応)。このデータを受け取った分析システムは、バックエンドで最終的な CLS 値を計算する必要があります。

デベロッパーは、これらすべてのケースを記憶して対処するのではなく、web-vitals JavaScript ライブラリを使用して CLS を測定できます。このライブラリでは、iframe のケースを除く上記のすべての要素が考慮されます。

import {onCLS} from 'web-vitals';

// Measure and log CLS in all situations
// where it needs to be reported.
onCLS(console.log);

CLS を改善する方法

現場でのレイアウト シフトを特定し、ラボデータを使用してそれらを最適化する方法について詳しくは、CLS の最適化に関するガイドをご覧ください。

参考情報

変更履歴

指標の測定に使用する API や、指標自体の定義にバグが見つかることもあります。そのため、必要な変更を行う必要が生じることがあります。また、こうした変更は、内部のレポートやダッシュボードに改善または回帰として表示されることがあります。

指標の実装または定義に対する変更はすべて、こちらの変更履歴に掲載されています。

これらの指標についてフィードバックがある場合は、web-vitals-feedback Google グループからお寄せください。