レイアウトの急な移動を避けてユーザー エクスペリエンスを向上させる方法
公開日: 2020 年 5 月 5 日、最終更新日: 2025 年 2 月 7 日
Cumulative Layout Shift(CLS)は、ウェブに関する主な指標の 3 つの指標のうちの 1 つです。ビューポート内で視覚コンテンツがどのくらい移動したかと、影響を受けた要素がどのくらい移動したかを組み合わせて、コンテンツの不安定さを測定します。
レイアウト シフトはユーザーの集中を妨げる可能性があります。記事を読み始めたときに、突然ページ上の要素が移動して、どこを読んでいたかわからなくなり、もう一度探す必要が生じたとします。これはウェブでよく見られる現象で、ニュースを読んでいるときや、[検索] ボタンや [カートに追加] ボタンをクリックしようとしたときなどに発生します。このようなエクスペリエンスは、視覚的に不快で、ユーザーにストレスを与えます。多くの場合、表示されている要素が、ページに別の要素が突然追加されたり、サイズ変更されたりしたために、強制的に移動させられたときに発生します。
優れたユーザー エクスペリエンスを提供するには、サイトで少なくとも 75% のページ訪問で CLS を 0.1 以下に収めるようにします。
他のコア ウェブ バイタルは秒またはミリ秒単位で測定される時間ベースの値ですが、CLS スコアはコンテンツがどの程度、どのくらい移動したかの計算に基づく単位のない値です。
このガイドでは、レイアウト シフトの一般的な原因を最適化する方法について説明します。
CLS が低い一般的な原因は次のとおりです。
- ディメンションのない画像。
- サイズのない広告、埋め込み、iframe。
- 広告、埋め込み、iframe など、サイズが指定されていない動的に挿入されたコンテンツ。
- ウェブフォント。
レイアウト シフトの原因を把握する
一般的な CLS の問題の解決策を検討する前に、CLS スコアとシフトの発生源を把握することが重要です。
ラボツールとフィールドでの CLS
デベロッパーが Chrome UX レポート(CrUX)で測定された CLS が正しくないと考えていることはよくあります。これは、Chrome DevTools や他のラボツールで測定した CLS と一致しないためです。Lighthouse などのウェブ パフォーマンス ラボツールでは、通常、ウェブ パフォーマンス指標を測定してガイダンスを提供するためにページの基本的な読み込みを行うため、ページの CLS 全体が表示されないことがあります(ただし、Lighthouse ユーザー フローでは、デフォルトのページ読み込み監査を超えて測定できます)。
CrUX はウェブに関する指標プログラムの Google データセットです。そのため、CLS は、ラボツールで測定されることが多い初回のページ読み込み時だけでなく、ページのライフサイクル全体を通じて測定されます。
ページの読み込み中にレイアウト変更が頻繁に発生するのは、ページを最初にレンダリングするために必要なリソースがすべて取得されるためですが、最初の読み込み後にレイアウト変更が発生することもあります。読み込み後のシフトの多くはユーザーの操作の結果として発生する可能性があるため、その操作から 500 ミリ秒以内に発生する限り、想定内のシフトとして CLS スコアから除外されます。
ただし、ユーザーが予期しない読み込み後のシフトは、条件を満たす操作がなかった場合でも含まれることがあります。たとえば、ページをさらにスクロールして遅延読み込みされたコンテンツが読み込まれ、シフトが発生した場合などです。読み込み後の CLS のその他の一般的な原因は、500 ミリ秒の猶予期間を超える遷移のインタラクション(シングルページ アプリなど)です。
PageSpeed Insights では、[実際のユーザーが体験していることを確認する] セクションに URL のユーザーが認識した CLS が表示され、[パフォーマンスの問題を診断する] セクションにラボベースの読み込み CLS が表示されます。これらの値の差は、読み込み後の CLS の結果である可能性があります。
読み込み CLS の問題を特定する
PageSpeed Insights の CrUX と Lighthouse の CLS スコアがほぼ一致している場合は、通常、Lighthouse によって検出された読み込み CLS の問題があることを示しています。この場合、Lighthouse は 2 つの監査で、幅と高さが指定されていないために CLS を引き起こしている画像に関する詳細情報を提供し、ページ読み込み時にシフトしたすべての要素と、それらの CLS への影響を一覧表示します。これらの監査は、CLS 監査でフィルタリングすることで確認できます。
DevTools の [パフォーマンス] パネルには、レイアウト シフトに関する豊富な情報が表示されます。
Layout Shift クラスタを示す紫色のバーが入力されます。ひし形をクリックすると、シフトのアニメーションと詳細が [概要] パネルに表示されます。レイアウト シフトは、[レイアウト シフト] トラックでハイライト表示されます。紫色の線はシフトをシフト クラスタにグループ化し、ひし形はクラスタ内の個々のシフトを示します。ひし形のサイズはシフトのサイズに比例するため、最も大きなシフトを特定できます。
シフトをクリックすると、シフトのアニメーションを含むポップアップが表示され、シフトの要素が紫色でハイライト表示されます。
また、Layout Shift レコードの [概要] ビューには、開始時間、シフトスコア、シフトされた要素が表示されます。これは、読み込み CLS の問題の詳細を把握するのに特に役立ちます。読み込み CLS の問題は、再読み込みパフォーマンス プロファイルで簡単に再現できるためです。
また、左側の [インサイト] パネルに表示される [レイアウト シフトの原因] インサイトにもリンクしています。このインサイトでは、上部に CLS の合計が表示され、レイアウト シフトの原因として考えられる理由も表示されます。
読み込み後の CLS の問題を特定する
CrUX と Lighthouse の CLS スコアの不一致は、読み込み後の CLS を示していることがよくあります。フィールドデータがないと、このような変化を追跡するのは困難です。フィールド データの収集については、フィールドで CLS 要素を測定するをご覧ください。
[パフォーマンス] パネルのライブ指標ビューでは、ページを操作して CLS スコアをモニタリングし、大きなレイアウト シフトを引き起こすインタラクションを特定できます。
DevTools を使用する代わりに、コンソールに貼り付けた Performance Observer を使用してレイアウト シフトを記録しながら、ウェブページを閲覧することもできます。
シフト モニタリングを設定したら、読み込み後の CLS の問題を再現してみます。CLS は、ユーザーがページをスクロールしているときに、遅延読み込みされたコンテンツがそのためのスペースを確保せずに完全に読み込まれると発生することがよくあります。ユーザーがポインタを合わせたときにコンテンツが移動するのも、読み込み後の CLS の一般的な原因です。これらの操作中にコンテンツがシフトした場合、500 ミリ秒以内であっても、意図しないシフトとしてカウントされます。
詳細については、レイアウト シフトをデバッグするをご覧ください。
CLS の一般的な原因を特定したら、Lighthouse のタイムスパン ユーザーフロー モードを使用して、レイアウト シフトの導入によって一般的なユーザーフローが回帰しないようにすることもできます。
フィールドで CLS 要素を測定する
フィールドで CLS をモニタリングすると、CLS が発生する状況を特定し、考えられる原因を絞り込むうえで非常に役立ちます。ほとんどのラボツールと同様に、フィールド ツールではシフトした要素のみが測定されますが、通常は原因を特定するのに十分な情報が得られます。CLS フィールド測定値を使用して、修正の優先度が最も高い問題を特定することもできます。
web-vitals ライブラリには、この追加情報を収集できるアトリビューション関数があります。詳細については、フィールドでのパフォーマンスのデバッグをご覧ください。他の RUM プロバイダも、同様にこのデータの収集と表示を開始しています。
CLS の一般的な原因
CLS の原因を特定したら、問題の修正に取り掛かることができます。このセクションでは、CLS の一般的な原因と、それを回避するための対策について説明します。
ディメンションのない画像
画像要素と動画要素には、必ず width と height のサイズ属性を含めてください。または、CSS aspect-ratio などを使用して必要なスペースを予約します。このアプローチにより、ブラウザは画像の読み込み中にドキュメント内の正しい量のスペースを割り当てることができます。
画像に対する width 属性と height 属性の履歴
ウェブの初期の頃、デベロッパーは <img> タグに width 属性と height 属性を追加して、ブラウザが画像の取得を開始する前にページに十分なスペースが割り当てられるようにしていました。これにより、リフローとレイアウトの再計算を最小限に抑えることができます。
<img src="puppy.jpg" width="640" height="360" alt="Puppy with balloons">
この例の width と height には単位が含まれていません。この「ピクセル」の寸法により、ブラウザはページのレイアウトで 640×360 の領域を確保します。実際のサイズがこのスペースと一致するかどうかに関係なく、画像はこのスペースに合わせて拡大されます。
レスポンシブ ウェブ デザインが導入されると、デベロッパーは width と height を省略し、代わりに CSS を使用して画像のサイズを変更するようになりました。
img {
width: 100%; /* or max-width: 100%; */
height: auto;
}
ただし、画像サイズが指定されていないため、ブラウザがダウンロードを開始して画像の寸法を特定するまで、そのためのスペースを割り当てることができません。画像が読み込まれると、そのスペースを確保するためにテキストがページの下に移動し、ユーザー エクスペリエンスが損なわれる可能性があります。
ここでアスペクト比が重要になります。画像のアスペクト比は、画像の幅と高さの比率です。通常、アスペクト比はコロンで区切られた 2 つの数値(16:9 や 4:3 など)で表されます。アスペクト比が x:y の場合、画像の幅は x ユニット、高さは y ユニットになります。
つまり、一方のディメンションがわかれば、もう一方のディメンションを特定できます。アスペクト比が 16:9 の場合:
- puppy.jpg の高さが 360 ピクセルの場合、幅は 360 x (16 / 9) = 640 ピクセルになります。
- puppy.jpg の幅が 640 ピクセルの場合、高さは 640 x (9 / 16) = 360 ピクセルになります。
画像のアスペクト比を把握することで、ブラウザは高さと関連領域に十分なスペースを計算して予約できます。
画像ディメンションを設定する最新のベスト プラクティス
最新のブラウザでは、画像のデフォルトのアスペクト比が画像の width 属性と height 属性に基づいて設定されるため、画像にこれらの属性を設定し、スタイルシートに上記の CSS を含めることで、レイアウト シフトを防ぐことができます。
<!-- set a 640:360 i.e a 16:9 aspect ratio -->
<img src="puppy.jpg" width="640" height="360" alt="Puppy with balloons">
すべてのブラウザは、要素の既存の width 属性と height 属性に基づいて、デフォルトのアスペクト比を追加します。
これは、画像の読み込み前に width 属性と height 属性に基づいてアスペクト比を計算します。この情報は、レイアウト計算の開始時に提供されます。画像の幅が指定されると(たとえば width: 100%)、アスペクト比を使用して高さが計算されます。
この aspect-ratio の値は、デフォルトのユーザー エージェント スタイルシートではなく、HTML の処理時に主要なブラウザによって計算されるため(詳しくはこちらの投稿をご覧ください)、値の表示が若干異なります。たとえば、Chrome では、[要素] パネルの [スタイル] セクションに次のように表示されます。
img[Attributes Style] {
aspect-ratio: auto 640 / 360;
}
Safari も同様に、HTML 属性のスタイルソースを使用します。Firefox では、この計算された aspect-ratio は [インスペクタ] パネルにまったく表示されませんが、レイアウトには使用されます。
上記のコードの auto 部分は、画像のダウンロード後に画像の寸法がデフォルトのアスペクト比をオーバーライドするため、重要です。画像の寸法が異なる場合、画像が読み込まれた後にレイアウト シフトが発生しますが、HTML が正しくない場合でも、画像が利用可能になったときに画像のアスペクト比が使用されるようになります。実際のアスペクト比がデフォルトと異なる場合でも、サイズが指定されていない画像のデフォルトの 0x0 サイズよりもレイアウト シフトが少なくなります。
アスペクト比とレスポンシブ画像の詳細については、メディア アスペクト比によるジャンクのないページ読み込みをご覧ください。
画像がコンテナ内にある場合は、CSS を使用して画像のサイズをコンテナの幅に合わせて変更できます。height: auto; を設定して、画像の高さに固定値を使用しないようにします。
img {
height: auto;
width: 100%;
}
レスポンシブ画像はどうですか?
レスポンシブ画像を使用する場合、srcset は、ブラウザが選択できる画像と、各画像のサイズを定義します。<img> の幅と高さの属性を設定できるようにするには、各画像で同じアスペクト比を使用する必要があります。
<img
width="1000"
height="1000"
src="puppy-1000.jpg"
srcset="puppy-1000.jpg 1000w, puppy-2000.jpg 2000w, puppy-3000.jpg 3000w"
alt="Puppy with balloons"
/>
画像の縦横比は、アート ディレクションによっても変わります。たとえば、狭いビューポートでは画像の切り抜きを含め、デスクトップでは画像全体を表示したい場合などです。
<picture>
<source media="(max-width: 799px)" srcset="puppy-480w-cropped.jpg" />
<source media="(min-width: 800px)" srcset="puppy-800w.jpg" />
<img src="puppy-800w.jpg" alt="Puppy with balloons" />
</picture>
Chrome、Firefox、Safari で、指定された <picture> 要素内の <source> 要素に width と height を設定できるようになりました。
<picture>
<source media="(max-width: 799px)" srcset="puppy-480w-cropped.jpg" width="480" height="400" />
<source media="(min-width: 800px)" srcset="puppy-800w.jpg" width="800" height="400" />
<img src="puppy-800w.jpg" alt="Puppy with balloons" width="800" height="400" />
</picture>
広告、埋め込み、その他の遅延読み込みコンテンツ
レイアウト シフトを引き起こす可能性があるのは画像だけではありません。広告、埋め込み、iframe、その他の動的に挿入されるコンテンツは、その後に表示されるコンテンツを下に移動させ、CLS を増加させる可能性があります。
広告は、ウェブ上のレイアウト シフトの最大の原因の一つです。広告ネットワークとパブリッシャーは、動的広告サイズに対応していることがよくあります。広告サイズを増やすと、クリック率が上がり、オークションで競合する広告が増えるため、パフォーマンスと収益が向上します。ただし、この場合、広告によって表示中のコンテンツがページの下に押し下げられるため、ユーザー エクスペリエンスが低下する可能性があります。
埋め込み可能なウィジェットを使用すると、YouTube の動画、Google マップの地図、ソーシャル メディアの投稿など、ポータブルなウェブ コンテンツをページに含めることができます。ただし、これらのウィジェットは、読み込まれる前にコンテンツのサイズを認識していないことがよくあります。そのため、埋め込みを提供するプラットフォームは、ウィジェットのスペースを常に予約しているわけではなく、最終的に読み込まれたときにレイアウト シフトが発生します。
これらの処理方法はすべて似ています。主な違いは、挿入されるコンテンツをどの程度制御できるかです。広告パートナーなどの第三者によって挿入される場合、挿入されるコンテンツの正確なサイズを把握できないことや、埋め込み内で発生するレイアウト シフトを制御できないことがあります。
遅延読み込みコンテンツのスペースを予約する
遅延読み込みコンテンツをコンテンツ フローに配置する場合、初期レイアウトでそのコンテンツのスペースを予約することで、レイアウト シフトを回避できます。
1 つの方法は、min-height CSS ルールを追加してスペースを予約することです。また、広告などのレスポンシブ コンテンツの場合は、ブラウザがサイズ指定のある画像に対して自動的に使用するのと同様の方法で、aspect-ratio CSS プロパティを使用します。
メディアクエリを使用して、フォーム ファクタ間の広告やプレースホルダのサイズの微妙な違いを考慮する必要がある場合があります。
広告など、高さが固定されていないコンテンツの場合、レイアウト シフトを完全に排除するために必要なスペースを正確に予約できないことがあります。小さいサイズの広告が配信される場合は、レイアウト シフトを回避するために大きいサイズのコンテナをスタイル設定するか、過去のデータに基づいて広告スロットのサイズを最も可能性の高いサイズに選択できます。この方法の欠点は、ページ上の空白スペースが増えることです。
代わりに、初期サイズを最小サイズに設定し、大きなコンテンツのシフトをある程度許容することもできます。前述のように min-height を使用すると、空の要素のデフォルト サイズである 0px と比較して、レイアウト シフトの影響を軽減しながら、必要に応じて親要素を拡大できます。
たとえば、広告が返されなかった場合はプレースホルダを表示して、予約済みのスペースが折りたたまれないようにします。要素用に確保されたスペースを削除すると、コンテンツを挿入した場合と同じくらいの CLS が発生する可能性があります。
読み込みが遅いコンテンツをビューポートの下部に配置する
ビューポートの上部近くに動的に挿入されたコンテンツは、ビューポートの下部に挿入されたコンテンツよりもレイアウト シフトが大きくなる傾向があります。ただし、ビューポートの任意の場所にコンテンツを挿入すると、多少のシフトが発生します。挿入するコンテンツのスペースを予約できない場合は、CLS への影響を軽減するため、ページの下部に配置することをおすすめします。
ユーザー操作なしで新しいコンテンツを挿入しない
サイトを読み込もうとしたときに、ビューポートの上部または下部に UI がポップインしてレイアウト シフトが発生した経験があるかもしれません。広告と同様に、ページの残りのコンテンツを移動させるバナーやフォームでよく発生します。
このような UI アフォーダンスを表示する必要がある場合は、読み込み時にページ内のコンテンツが突然移動しないように、ビューポート内に十分なスペースを事前に確保してください(プレースホルダやスケルトン UI を使用するなど)。または、コンテンツをオーバーレイして、要素がドキュメント フローの一部にならないようにします。これらのタイプのコンポーネントに関するその他の推奨事項については、Cookie 通知に関するベスト プラクティスの投稿をご覧ください。
場合によっては、コンテンツを動的に追加することがユーザー エクスペリエンスの重要な要素となることがあります。たとえば、商品アイテムのリストに商品を追加で読み込む場合や、ライブフィードのコンテンツを更新する場合などです。このようなケースで予期しないレイアウト シフトを回避するには、いくつかの方法があります。
- 固定サイズのコンテナ内で古いコンテンツを新しいコンテンツに置き換えるか、カルーセルを使用して、切り替え後に古いコンテンツを削除します。新しいコンテンツが読み込まれる間に誤ってクリックまたはタップされるのを防ぐため、切り替えが完了するまでリンクとコントロールを無効にしてください。
- ユーザーが新しいコンテンツの読み込みを開始できるようにして、シフトに驚かないようにする(「もっと読み込む」ボタンや「更新」ボタンなど)。ユーザーが操作する前にコンテンツをプリフェッチして、すぐに表示できるようにすることをおすすめします。なお、ユーザー入力から 500 ミリ秒以内に発生するレイアウト シフトは CLS にカウントされません。
- コンテンツを画面外でシームレスに読み込み、利用可能であることをユーザーに通知する(たとえば、「上へスクロール」ボタンを表示する)
アニメーション
CSS プロパティ値の変更により、ブラウザがこれらの変更に対応する必要が生じることがあります。box-shadow や box-sizing などの値は、レイアウト、ペイント、合成をトリガーします。移動する要素が独自のレイヤにある場合でも、top プロパティと left プロパティを変更するとレイアウト シフトが発生します。これらのプロパティを使用したアニメーションは避けてください。
他の CSS プロパティは、レイアウトの再計算をトリガーせずに変更できます。たとえば、transform アニメーションを使用して要素を変換、拡大縮小、回転、傾斜させることができます。
translate を使用した合成アニメーションは他の要素に影響しないため、CLS にはカウントされません。合成されていないアニメーションも、レイアウトの再実行を引き起こしません。レイアウト シフトをトリガーする CSS プロパティについて詳しくは、ハイ パフォーマンス アニメーションをご覧ください。
ウェブフォント
通常、ウェブフォントのダウンロードとレンダリングは、ウェブフォントがダウンロードされる前に次のいずれかの方法で処理されます。
- 代替フォントがウェブフォントに置き換えられ、FOUT(Flash of Unstyled Text)が発生します。
- ウェブフォントが利用可能になり、テキストが表示されるまで、「見えない」テキストはフォールバック フォントを使用して表示されます(FOIT - 見えないテキストのフラッシュ)。
どちらの方法でもレイアウト シフトが発生する可能性があります。テキストが非表示の場合でも、フォールバック フォントを使用してレイアウトされるため、ウェブフォントが読み込まれると、テキスト ブロックと周囲のコンテンツは、表示フォントの場合と同じように移動します。
次のツールを使用すると、テキストの移動を最小限に抑えることができます。
font-display: optionalを使用すると、ウェブフォントが最初のレイアウト時に利用可能な場合にのみ使用されるため、再レイアウトを回避できます。- 適切なフォールバック フォントが使用されていることを確認します。たとえば、
font-family: "Google Sans", sans-serif;を使用すると、"Google Sans"の読み込み中にブラウザのsans-serifフォールバック フォントが使用されます。font-family: "Google Sans"のみを使用してフォールバック フォントを指定しないと、デフォルトのフォントが使用されます。Chrome では、デフォルトのsans-serifフォントよりも一致率の低いセリフフォントである「Times」が使用されます。 - フォントのフォールバックの改善に関する投稿で説明されているように、新しい
size-adjust、ascent-override、descent-override、line-gap-overrideAPI を使用して、フォールバック フォントとウェブ フォントのサイズの違いを最小限に抑えます。 - フォント読み込み API を使用すると、必要なフォントを取得する時間を短縮できます。
<link rel=preload>を使用して、重要なウェブフォントをできるだけ早く読み込みます。フォントをプリロードすると、ファースト ペイントを満たす可能性が高くなり、レイアウト シフトが発生しなくなります。
フォントに関するその他のベスト プラクティスについては、フォントに関するベスト プラクティスをご覧ください。
ページがバックフォワード キャッシュの対象となるようにして CLS を削減する
CLS スコアを低く保つための非常に効果的な手法は、ウェブページがバックフォワード キャッシュ(bfcache)の対象となるようにすることです。
bfcache は、ページから移動した後、短時間だけブラウザのメモリにページを保持します。そのため、ページに戻ると、移動したときの状態がそのまま復元されます。つまり、ページが完全に読み込まれた状態がすぐに利用可能になり、読み込み中に通常発生するレイアウトのずれが、前述の理由のいずれかによって発生することはありません。
これにより、最初のページ読み込みでレイアウト シフトが発生する可能性はありますが、ユーザーがページを戻って閲覧する際に、同じレイアウト シフトが繰り返し発生することはありません。初期読み込みでもシフトを回避することを常に目指すべきですが、完全に解決するのが難しい場合は、bfcache ナビゲーションでシフトを回避することで、影響を軽減できます。
多くのサイトで、戻る操作と進む操作がよく行われます。たとえば、目次ページ、カテゴリページ、検索結果に戻るなどです。
この変更を Chrome にロールアウトしたところ、CLS が大幅に改善されました。
バックフォワード キャッシュはすべてのブラウザでデフォルトで使用されますが、さまざまな理由により、一部のサイトはバックフォワード キャッシュの対象外となります。bfcache ガイドで、bfcache の使用を妨げる問題をテストして特定する方法について詳しく確認し、この機能を最大限に活用してサイトの CLS スコア全体を改善してください。
まとめ
このガイドの前半で説明したように、CLS を特定して改善するための手法は数多くあります。Core Web Vitals には許容範囲が組み込まれているため、CLS を完全に排除できない場合でも、これらの手法の一部を使用することで影響を軽減できます。これにより、制限内に収まり、ウェブサイトのユーザー エクスペリエンスを向上させることができます。