Cumulative Layout Shift(CLS)

対応ブラウザ

  • 77
  • 79
  • x
  • x

ソース

Cumulative Layout Shift(CLS)は、安定した Core Web Vitals 指標です。ユーザーが予期しないレイアウト シフトが発生する頻度を定量化できるため、これは視覚的な安定性を測定するためのユーザー中心の重要な指標です。CLS を低くすると、ページを快適なものにすることができます。

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

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

ページ コンテンツの予期しない移動は、通常、リソースが非同期で読み込まれる場合や、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 つある距離分数の例
距離の割合は、要素がビューポート全体にわたって移動した距離を測定します。

この例では、ビューポートの最大寸法は高さであり、不安定な要素がビューポートの高さの 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 です。

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

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

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

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

矢印は、不安定な要素が開始位置から移動した距離を表します。青い矢印で表される「Zebra」要素が、ビューポートの高さの約 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 エントリをグループ化して、最大セッション値を計算します。リファレンス実装については、web vitals JavaScript ライブラリのソースコードをご覧ください。

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

指標と API の違い

  • ページがバックグラウンドで読み込まれた場合、またはブラウザがコンテンツをペイントする前にバックグラウンドに設定されていた場合は、CLS 値をレポートしません。
  • ページがバックフォワード キャッシュから復元された場合、CLS 値をゼロにリセットする必要があります。これは、ユーザーが個別のページ訪問として見なすためです。
  • この API は iframe 内で発生するシフトに対して layout-shift エントリをレポートしませんが、この指標はページのユーザー エクスペリエンスの一部であるため、レポートします。これは、CrUX と RUM の違いを示している可能性があります。CLS を適切に測定するには、iframe を含める必要があります。サブフレームは、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 グループからお知らせください。