Cumulative Layout Shift(CLS)

対応ブラウザ

  • Chrome: 77。
  • Edge: 79.
  • Firefox: サポートされていません。
  • Safari: サポートされていません。

ソース

予期しないレイアウトの変化は、テキストが突然移動して読み進めにくくなったり、間違ったリンクやボタンをクリックしたりするなど、さまざまな方法でユーザー エクスペリエンスを損なう可能性があります。場合によっては、深刻な損傷につながることもあります。

レイアウトが突然変化し、キャンセルしようとしていた大量注文をユーザーが確認することになります。

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

開発中のサイトの機能とユーザーが実際に使用するサイトの機能の違いが、この問題を悪化させます。次に例を示します。

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

累積レイアウト シフト(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 です。

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

安定した要素と不安定な要素、ビューポートの切り抜きがあるレイアウト シフトの例
この並べ替えられたリストに名前が増えると、既存の名前が移動してアルファベット順が維持されます。

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

リストの最初の項目(「猫」)はフレーム間で開始位置が変化しないため、安定しています。同様に、リストに追加された新しいアイテムは以前 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 エントリをセッションにグループ化し、セッションの最大値を計算する必要があります。CLS の計算方法に関するリファレンス実装が含まれている web vitals JavaScript ライブラリのソースコードをご覧ください。

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

指標と API の違い

  • ページがバックグラウンドで読み込まれた場合、またはブラウザがコンテンツをペイントする前にバックグラウンドに移行された場合は、CLS 値を報告しないでください。
  • ページがバックフォワード キャッシュから復元された場合、ユーザーは別のページ訪問として認識するため、CLS 値はゼロにリセットする必要があります。
  • 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 グループで送信してください。