レイアウト シフトをデバッグする

レイアウト シフトを特定して修正する方法を学習します。

Katie Hempenius
Katie Hempenius

この記事の前半では、レイアウト シフトのデバッグ用ツールについて説明します。後半では、レイアウト シフトの原因を特定する際の考え方について説明します。

ツール

Layout Instability API

Layout Instability API は レイアウト シフトを測定してレポートするためのブラウザ メカニズムです。以下のためのすべてのツール レイアウト シフトのデバッグ(DevTools を含む)は、 Layout Instability APIただし、Layout Instability API を直接使用すると、 優れたデバッグ ツールであり、その柔軟性に優れています。

用途

同じコード スニペットCumulative Layout Shift(CLS)の レイアウト シフトのデバッグに使用できます。以下のスニペットは、レイアウトに関する情報を記録します。 コンソールに移動できますこのログを調べると、 レイアウト シフトがいつ、どこで、どのように発生したかという問題です。

let cls = 0;
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

このスクリプトを実行するときは、次の点に注意してください。

  • buffered: true オプションは、 PerformanceObserver ブラウザーのパフォーマンスエントリ バッファ オブザーバーのスコープより前に作成されたパフォーマンス エントリの 初期化します。その結果、PerformanceObserver は初期化の前後に発生したレイアウト シフトを報告します。保持する コンソールログを調べることをおすすめします。初期のレイアウト シフトでは、 報告のバックログを反映しているので、 調整できます。
  • パフォーマンスに影響しないように、PerformanceObserver はメインスレッドがアイドル状態になるまで待機してから、レイアウトのずれを報告します。そのため、メインスレッドの負荷によっては、レイアウト シフトが発生してからコンソールにログに記録されるまでに若干の遅延が生じることがあります。
  • このスクリプトは、ユーザー入力から 500 ミリ秒以内に発生したレイアウト シフトを無視するため、CLS にはカウントされません。

レイアウト シフトに関する情報は、次の 2 つの API を組み合わせて報告します。 LayoutShiftLayoutShiftAttribution インターフェースです。これらの各インターフェースについては、 以降のセクションで説明します

LayoutShift

各レイアウト シフトは、LayoutShift インターフェースを使用して報告されます。エントリの内容は次のようになります。

duration: 0
entryType: "layout-shift"
hadRecentInput: false
lastInputTime: 0
name: ""
sources: (3) [LayoutShiftAttribution, LayoutShiftAttribution, LayoutShiftAttribution]
startTime: 11317.934999999125
value: 0.17508567530168798

上記のエントリはレイアウト シフトを示しており、レイアウト シフトの間に 3 つの DOM 要素が変化しています。 なります。この特定のレイアウト シフトのレイアウト シフトのスコアは 0.175 でした。

レイアウト シフトのデバッグに最も関連する LayoutShift インスタンスのプロパティは次のとおりです。

プロパティ 説明
sources sources プロパティには、レイアウト シフト中に移動した DOM 要素のリストが表示されます。この配列には最大 5 つのソースを含めることができます。レイアウト シフトの影響を受ける要素が 5 つ以上ある場合は、レイアウト シフトの影響が大きい上位 5 つ(レイアウトの安定性への影響で測定)が報告されます。この情報は、LayoutShiftAttribution インターフェースを使用して報告されます(詳しくは後述)。
value value プロパティは、特定のレイアウト シフトのレイアウト シフトのスコアをレポートします。
hadRecentInput hadRecentInput プロパティは、ユーザー入力から 500 ミリ秒以内にレイアウト シフトが発生したかどうかを示します。
startTime startTime プロパティは、レイアウト シフトが発生したタイミングを示します。startTime はミリ秒単位で示され、ページの読み込みが開始された時間を基準に測定されます。
duration duration プロパティは常に 0 に設定されます。このプロパティは PerformanceEntry インターフェースから継承されます(LayoutShift インターフェースは PerformanceEntry インターフェースを拡張します)。ただし、レイアウト シフト イベントには継続時間の概念が適用されないため、0 に設定されます。PerformanceEntry インターフェースの詳細については、仕様をご覧ください。

LayoutShiftAttribution

LayoutShiftAttribution インターフェースは、単一の DOM 要素の単一シフトを記述します。レイアウト シフト中に複数の要素がシフトした場合、sources プロパティに複数のエントリが含まれています。

たとえば、次の JSON は、<div id='banner'> DOM 要素が y: 76 から y:246 に下方にシフトするという、1 つのソースによるレイアウト シフトに対応しています。

// ...
  "sources": [
    {
      "node": "div#banner",
      "previousRect": {
        "x": 311,
        "y": 76,
        "width": 4,
        "height": 18,
        "top": 76,
        "right": 315,
        "bottom": 94,
        "left": 311
      },
      "currentRect": {
        "x": 311,
        "y": 246,
        "width": 4,
        "height": 18,
        "top": 246,
        "right": 315,
        "bottom": 264,
        "left": 311
      }
    }
  ]

node プロパティは、シフトした HTML 要素を示します。カーソルを合わせると プロパティが表示され、対応するページ要素がハイライト表示されます。

previousRect プロパティと currentRect プロパティは、画像のサイズと位置を報告します。 作成されます。

  • x 座標と y 座標は、要素の左上隅の x 座標と y 座標をそれぞれ報告します。
  • width プロパティと height プロパティは、それぞれ幅と高さを報告します。 渡します。
  • toprightbottomleft プロパティは x または y をレポートする 要素のエッジに対応する座標値。つまり、top の値は y と等しく、bottom の値は y+height と等しい。

previousRect のすべてのプロパティが 0 に設定されている場合、要素がビュー内に移動したことを意味します。currentRect のすべてのプロパティが 0 に設定されている場合、要素がビューの外側に移動したことを意味します。

これらの出力を解釈する際に理解しておくべき最も重要なことの一つは、 ソースとしてリストされている要素が、 レイアウト シフトです。ただし、これらの要素は間接的に 問題の「根本原因」に関連する軽減できます。次に例を示します。

例 1

このレイアウト シフトは、1 つのソース(要素 B)で報告されます。ただし、 このレイアウト シフトの根本原因は、要素 A のサイズ変更です。

要素のサイズ変更によるレイアウト シフトの例

例 2

この例のレイアウト シフトは、2 つのソース(要素 A)によって報告されます。 要素 B を指定しますこのレイアウト シフトの根本的な原因は、 要素 A から抽出されます。

要素の位置の変化によるレイアウト シフトの例

例 3

この例のレイアウト シフトは、1 つのソース(要素 B)で報告されます。要素 B の位置を変更した結果、このレイアウト シフトが発生しました。

要素の位置の変更によってレイアウトがずれる例

例 4

この例では、要素 B のサイズは変更されますが、レイアウト シフトは発生しません。

要素のサイズが変化するがレイアウト シフトを発生させない例

Layout Instability API によって DOM の変更が報告される方法のデモをご覧ください。

DevTools

パフォーマンス パネル

DevTools の [パフォーマンス] パネルの [エクスペリエンス] ペインには、特定のパフォーマンス トレース中に発生したすべてのレイアウト シフトが表示されます。ユーザー操作から 500 ミリ秒以内に発生したレイアウト シフトは CLS にカウントされないため、表示されます。[リニューアル版] パネルのハイライト表示で、特定のレイアウト シフトにカーソルを合わせます。 該当する DOM 要素。

DevTools の [Network] パネルに表示されたレイアウト シフトのスクリーンショット

レイアウト シフトの詳細を表示するには、[レイアウト シフト] をクリックして [Summary] ドロワーを開きます。要素のディメンションの変更のリストが [width, height] の形式を使用します。要素の位置の変更がリストされます。 [x,y] の形式を使用します。Had recent input プロパティは、ユーザー操作から 500 ミリ秒以内にレイアウト シフトが発生したかどうかを示します。

DevTools の [Summary] のスクリーンショットLayout Shift のタブ

レイアウト シフトの継続時間については、[イベントログ] タブを開きます。レイアウト シフトの所要時間は、 赤色のレイアウト シフトの長方形の長さの [Experience] ペイン。

DevTools の「イベントログ」のスクリーンショットLayout Shift のタブ

パフォーマンスパネルの使用の詳細については、パフォーマンス 分析 リファレンスをご覧ください。

レイアウト シフト領域をハイライト表示する

レイアウト シフトの領域をハイライト表示すると、 レイアウト シフトの場所とタイミングを一目で一目で把握できる 表示されます。

DevTools で Layout Shift Regions を有効にするには、[Settings] >その他のツール > レンダリング >Layout Shift Regions に移動してから、デバッグするページを更新します。 レイアウト シフトが発生した領域は、紫色でハイライト表示されます。

レイアウト シフトの原因を特定するための思考プロセス

レイアウトのずれがいつ、どのように発生したかにかかわらず、以下の手順でレイアウトのずれの原因を特定できます。このステップは ただし、Lighthouse を使用すると、 最初のページ読み込み中に発生したレイアウト シフトのみを特定できます。また、Lighthouse は、明示的な幅と高さがない画像要素など、レイアウトのずれの原因の一部についてのみ、推奨事項を提供できます。

レイアウト シフトの原因を特定する

レイアウト シフトは、次のような場合に発生することがあります。

  • DOM 要素の位置の変更
  • DOM 要素のサイズの変更
  • DOM 要素の挿入または削除
  • レイアウトをトリガーするアニメーション

特に、シフトされた要素の直前の DOM 要素は、レイアウト シフトの「原因」となる可能性が高い要素です。したがって、レイアウト シフトが発生した理由を調査する際は、次の点を考慮してください。

  • 前の要素の位置やサイズは変わりましたか?
  • 移動された要素の前に DOM 要素が挿入または削除されたか?
  • 移動された要素の位置が明示的に変更されましたか?

前の要素がレイアウト シフトの原因ではなかった場合は、他の前の要素と近くの要素を検討して検索を続けます。

また、レイアウト シフトの方向と距離からもヒントになります。 特定します。たとえば、下方向への大きなシフトは DOM 要素の挿入を示すことが多く、1 ピクセルまたは 2 ピクセルのレイアウト シフトは、競合する CSS スタイルの適用や、ウェブフォントの読み込みと適用を示します。

フォント交換によって発生したレイアウト シフトを示す図
この例では、フォント交換によりページ要素が 5 ピクセル上方にシフトしました。

レイアウト移動イベントを引き起こす最も一般的な動作は次のとおりです。

要素の位置の変更(他の要素の移動によるものではない)

この種の変化は、多くの場合、次のような結果によって発生します。

  • 遅れて読み込まれるスタイルシートや、以前に宣言されたスタイルを上書きするスタイルシート。
  • アニメーションと切り替え効果。

要素の寸法の変更

この種の変化は、多くの場合、次のような結果によって発生します。

  • 遅れて読み込まれるスタイルシート、または以前に宣言されたスタイルを上書きするスタイルシート。
  • width 属性と height 属性のない画像と iframe 「スロット」表示されます。
  • width 属性または height 属性のないテキスト ブロックは、 表示されます。

DOM 要素の挿入または削除

多くの場合、これは次のような原因で発生します。

  • 広告やその他のサードパーティの埋め込みの挿入。
  • バナー、アラート、モーダルの挿入。
  • 既存のコンテンツの上に追加のコンテンツを読み込む無限スクロールなどの UX パターン。

レイアウトをトリガーするアニメーション

トリガーされるアニメーション効果には、 あります。共通 例として、DOM 要素が「アニメーション化」されている場合プロパティをインクリメントして CSS を使用せず、topleft など transform プロパティです。詳細については、高パフォーマンスの CSS アニメーションを作成する方法をご覧ください。

レイアウト シフトの再現

再現できないレイアウトのずれは修正できません。シンプルでありながら サイトのレイアウトを把握するのに最も効果的な方法 目標に到達するまでに 5 ~ 10 分かかります。 レイアウト シフトをトリガーできます。コンソールを開いたまま、Layout Instability API を使用してレイアウトのずれを報告します。

レイアウトのずれが見つけにくい場合は、別のデバイスと接続速度でこの演習を繰り返すことを検討してください。特に、低速の 接続速度を測定すると、レイアウト シフトを簡単に特定できます。また、debugger ステートメントを使用すると、レイアウト シフトを簡単にステップスルーできます。

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      debugger;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

最後に、開発中に再現できないレイアウトの問題については、 Layout Instability API とフロントエンド ロギングツールを組み合わせて使用する場合 問題に関するより詳細な情報を収集できます。チェックアウト ページ上で移動された最大要素をトラッキングするコードのサンプルをご覧ください。