Cumulative Layout Shift(CLS)

対応ブラウザ

  • Chrome: 77。 <ph type="x-smartling-placeholder">
  • Edge: 79。 <ph type="x-smartling-placeholder">
  • Firefox: サポートされていません。 <ph type="x-smartling-placeholder">
  • Safari: サポートされていません。 <ph type="x-smartling-placeholder">

ソース

<ph type="x-smartling-placeholder">

予期しないレイアウト シフトは、テキストが突然動くと読み上げ中にその場所がわからなくなったり、間違ったリンクやボタンをクリックしてしまうなど、さまざまな形でユーザー エクスペリエンスに悪影響を及ぼします。場合によっては、これが深刻な被害を受けることもあります。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
レイアウトが突然変わると、ユーザーは意図した大規模な注文を確定する キャンセルします。

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

開発中のサイトの機能とユーザー エクスペリエンスの違いが、この問題を悪化させています。例:

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

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

CLS とは

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

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

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

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

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
セッション ウィンドウの例。青色のバーは、個々のレイアウト シフトのスコアを表します。
で確認できます。
<ph type="x-smartling-placeholder">

優れた CLS スコアとは

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

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder"></ph> CLS の良好な値は 0.1 以下で、低い値は 0.25 を上回っており、その中間値は改善が必要
良好な CLS 値は 0.1 以下です。低い値は 0.25 より大きくなります。

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

レイアウト シフトの詳細

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

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

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

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

layout shift score = impact fraction * distance fraction

影響分率

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

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

<ph type="x-smartling-placeholder">
</ph> 1 つの不安定な要素が影響する割合の例 <ph type="x-smartling-placeholder">
</ph> 要素の位置が変わった場合は、その前の位置と現在の位置の両方が影響率に影響します。

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

距離の割合

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

<ph type="x-smartling-placeholder">
</ph> 不安定な要素が 1 つある距離の割合の例 <ph type="x-smartling-placeholder">
</ph> 距離の割合は、要素がビューポート上でどこまで移動したかを測定します。

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

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

<ph type="x-smartling-placeholder">

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

<ph type="x-smartling-placeholder">
</ph> 複数の Stable 要素と _unstable 要素を複数含むレイアウト シフトの例 <ph type="x-smartling-placeholder">
</ph> グレーのボックスの下部にボタンを追加すると、緑色のボックスが押し下げられ、部分的にビューポートの外に出ます。

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

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

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

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

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

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

<ph type="x-smartling-placeholder">
</ph> 安定した要素と不安定な要素とビューポートのクリッピングがあるレイアウト シフトの例 <ph type="x-smartling-placeholder">
</ph> 並べ替えたリストに表示される名前が増えると、既存の名前もアルファベット順に移動します。

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

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

赤色の点線の長方形は、これら 3 つの不安定な要素の結合を表します。領域の前後の領域。この例では、ビューポートの領域の約 60%(0.60影響割合)を占めています。

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

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

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

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

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

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

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

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

<ph type="x-smartling-placeholder">

アニメーションと遷移

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

prefers-reduced-motion のブラウザ設定を必ず遵守してください。アニメーションによって悪影響や注意の問題が生じることがあります。

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

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

CLS の測定方法

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

<ph type="x-smartling-placeholder">

フィールド ツール

ラボツール

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

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

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

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 を測定できます。CLS は、iframe のケースを除く上記のすべてのケースに対応しています。

import {onCLS} from 'web-vitals';

// Measure and log CLS in all situations
// where it needs to be reported.
onCLS(console.log);
<ph type="x-smartling-placeholder">

CLS を改善する方法

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

参考情報

変更履歴

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

管理しやすくするために、これらの指標の実装または定義に対するすべての変更は、こちらの変更履歴で確認できます。

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