Cumulative Layout Shift(CLS)

Milica Mihajlija
Milica Mihajlija
Philip Walton
Philip Walton

対応ブラウザ

  • 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 つの部分は、不安定な要素が移動した際のビューポートからの相対距離を測定します。距離の割合は、フレーム内で不安定な要素が移動した最大の水平方向または垂直方向の距離を、ビューポートの最大の寸法(幅または高さのいずれか大きい方)で割った値です。

不安定な要素が 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 グループで送信してください。