CLS を改善する — レイアウトシフトを防ぐ
CLS は、ページの表示中に要素が予期せずずれた量を累積して測る、Core Web Vitals の視覚的安定性の指標です。読もうとした行が急に動く、押すつもりのないボタンを押してしまう——その原因を数値化したものです。良好とされる 0.1 以下の基準、ずれを生む主な原因、そして場所を先に予約して防ぐ具体策を、コード付きで説明します。
CLS とは何ですか?
CLS(Cumulative Layout Shift)は、ページの表示中に要素が予期せずずれた量を累積して測る、Core Web Vitals の視覚的安定性の指標です。読もうとした行が急に下へ動く、押そうとしたボタンが移動する、といった「不意のずれ」を数値化します。値が小さいほど安定しており、利用者の誤操作やストレスが少ないことを意味します。
読み込みの途中でリンクを押そうとした瞬間、広告が割り込んで別の場所を押してしまった——CLS はこの「不意のずれ」を数値化した指標です。 LCP が表示の速さ、INP が反応の速さを測るのに対し、CLS は表示の安定性を測ります。 速く表示されても、そのあと内容がガタガタ動くページは、利用者にとって快適ではありません。
ポイントは「予期しない」ずれだけを数えることです。利用者が自分でボタンを押して開いたメニューのように、 本人が予期している動きは対象になりません。あくまで、読んでいる最中に勝手に起きるずれが問題視されます。
CLS はどのくらいなら良好ですか?
良好の基準は 0.1 以下です。0.1 を超え 0.25 までが「要改善」、0.25 を超えると「不良」と判定されます。この値は実際の訪問者から集めた計測の 75 パーセンタイルで評価されるため、大多数の利用者が安定した表示を体験して初めて良好になります。秒でも枚数でもない無次元のスコアで、ずれの大きさと範囲の掛け算で決まります。
| 評価 | CLS の値 | 利用者の体感 |
|---|---|---|
| 良好 | 0.1 以下 | ずれをほとんど感じない |
| 要改善 | 0.1 超 〜 0.25 | ときどき内容が動いて気になる |
| 不良 | 0.25 超 | 誤タップや読み直しが頻発する |
この値は実際の訪問者から集めた計測の 75 パーセンタイルで評価されます。平均ではありません。 つまり、訪問者の 75% が 0.1 以下を体験して初めて良好になります。手元の 1 台で 0 だったとしても、 低速回線の利用者で広告や画像の到着が遅れれば、そこでずれが起きて数値は悪化します。
スコアは「ずれの大きさ×範囲」で決まる
1 回のずれのスコアは、画面のどれだけの範囲が動いたか(impact fraction)と、どれだけの距離を動いたか(distance fraction)の掛け算で計算されます。 画面の大部分を占める要素が大きく飛ぶほど、スコアは跳ね上がります。
「Cumulative(累積)」の名のとおり、CLS はページ滞在中に起きたずれを足し合わせた値です。ただし単純な総和ではなく、連続して起きたずれをひとまとまり(セッションウィンドウ)にまとめ、その中で最大の合計を採用します。 1 つのウィンドウは最長 5 秒、ずれの間隔が 1 秒空くと区切られます。だらだら長いページでも、 最も揺れた瞬間の合計で評価される仕組みです。
レイアウトのずれは何が原因で起きますか?
原因の大半は、表示前に場所を確保していない要素が、後から実寸で割り込むことです。具体的にはサイズ未指定の画像・動画・iframe、高さを予約していない広告や埋め込み枠、後から挿入されるバナーや通知、そして Web フォントの切り替わりの 4 つが典型です。いずれも「最初は無かった領域があとで広がり、既存の内容を押し下げる」点が共通しています。
原因は多様に見えて、根っこは 1 つです。「表示を始める時点で、要素の最終的な大きさが分かっていない(=場所を予約していない)」こと。 あとから実寸が判明したり、新しい要素が割り込んだりした瞬間に、すでに表示されていた内容が押しのけられます。 主な発生源を対策とセットで整理すると次のとおりです。
| ずれの原因 | 何が起きるか | 対策 |
|---|---|---|
| サイズ未指定の画像・動画・iframe | 実寸が判明した瞬間に箱が広がり、下の内容を押し下げる | width/height 属性か aspect-ratio で場所を予約 |
| 広告・埋め込みの枠 | 遅れて挿入され、確保していない高さぶん本文が飛ぶ | 想定サイズの高さを先に確保する |
| 後から挿入されるバナー・通知 | 既存コンテンツの上に割り込み、全体を下へずらす | 上に差し込まない・固定領域を予約する |
| Web フォントの切り替え | 代替フォントから本フォントへ替わる際に字幅・字高が変わる | font-display と size-adjust で寸法差を詰める |
画像や動画のずれはどう防ぎますか?
画像・動画・iframe に width と height 属性を指定し、ブラウザに表示前から縦横比を伝えます。属性があれば、ダウンロードが終わる前に正しい大きさの場所が予約され、あとから画像が入っても既存の内容が動きません。CSS で幅を可変にする場合も属性は残し、height: auto を併用します。属性を使えない要素には aspect-ratio で比率を指定します。
<!-- 画像は width / height 属性で「表示前の場所」を予約する。
属性があればブラウザが aspect-ratio を自動計算し、
ダウンロード完了前に正しい大きさの箱を空けておく -->
<img src="/photo.webp" width="1200" height="800" alt="製品の外観">
<!-- CSS で幅を可変にしても、属性は必ず残す。height:auto で比率を保つ -->
<style>
img { max-width: 100%; height: auto; }
</style>
<!-- 動画・iframe は width/height 属性が効きにくい。aspect-ratio で比率を固定する -->
<div style="aspect-ratio: 16 / 9">
<iframe src="..." style="width:100%; height:100%; border:0"></iframe>
</div>width / height 属性は「昔の書き方」ではありません。現代のブラウザはこの 2 つから aspect-ratio を自動計算し、画像のダウンロードが終わる前に、正しい大きさの箱を空けておきます。CSS で max-width: 100% を当てて幅を可変にしても、 属性は付けたままにしてください。属性を消すと予約が効かなくなり、画像が届いた瞬間に本文が飛びます。
動画プレーヤーや iframe の埋め込みは、外側のコンテナに aspect-ratio を指定して比率を固定するのが確実です。 レスポンシブ対応で画像を出し分ける場合も、各ソースの縦横比を揃えておけば、切り替わりでずれることがありません。
広告や埋め込み枠のずれはどう防ぎますか?
枠が埋まる前に、想定サイズぶんの高さをあらかじめ確保しておきます。広告・SNS 埋め込み・iframe は読み込みが遅れて後から挿入されるため、場所を予約していないと本文が突然下へ飛びます。よく配信されるサイズの最小高さを min-height で確保し、枠が埋まらなくても高さを維持して潰さないのが要点です。空白は CLS より安いと割り切ります。
/* 広告・埋め込み枠: 中身が届く前に高さを予約する。
これをしないと、挿入された瞬間に本文が下へ飛んで CLS が跳ねる */
.ad-slot {
min-height: 250px; /* 300x250 を想定した最小高さ */
contain: layout; /* 中の変化を外側へ波及させない */
}
/* 遅れて出るコンテンツは、比率で場所を先取りしておく手もある。
背景色を敷いておくと、読み込み中のちらつきも目立たない */
.embed {
aspect-ratio: 16 / 9;
background: #f2f2f2;
}広告や SNS 埋め込みは、本文より遅れて非同期に挿入されます。場所を予約していなければ、挿入された瞬間にそのぶんの高さだけ本文が下へ飛び、ちょうど読んでいた行を見失わせます。 対策は、枠が埋まる前から高さを確保しておくことに尽きます。
後から表示されるバナーやフォントのずれはどうしますか?
後から挿入する要素は既存コンテンツの上に割り込ませず、あらかじめ場所を空けておきます。同意バナーや通知は画面上部に差し込むと本文全体を押し下げるため、オーバーレイで重ねるか固定領域を先に確保します。Web フォントの切り替えによるずれは、font-display と size-adjust で代替フォントとの字形差を詰め、先読みで切り替えを早めて抑えます。
Cookie 同意バナー・お知らせ・キャンペーン告知などを、JavaScript で本文の一番上に差し込むのは典型的な失敗です。 すでに表示されていたコンテンツ全体が、バナーの高さぶん一気に下へ押し下げられます。対策の方針は 2 つあります。
- 重ねる — 本文を押し下げず、
position: fixedなどで上に覆いかぶせる(オーバーレイ) - 先に空ける — 差し込む位置に、あらかじめ同じ高さの領域を確保しておく
Web フォントの切り替えによるずれ
Web フォントは読み込みに時間がかかるため、その間の表示には 2 つの挙動があります。文字を隠して待つFOIT(Flash of Invisible Text)と、まず代替フォントで表示してから差し替えるFOUT(Flash of Unstyled Text)です。差し替えの瞬間に字幅や行の高さが変わると、テキストがずれて CLS になります。
/* Web フォント切り替え(FOIT / FOUT)でのずれを抑える。
font-display で不可視テキストを避け、
size-adjust と各 override で代替フォントとの寸法差を詰める */
@font-face {
font-family: "MyFont";
src: url("/f.woff2") format("woff2");
font-display: swap; /* 読み込み中も代替フォントで即表示する */
size-adjust: 97%; /* 全体の字幅・字高を代替フォントに合わせる */
ascent-override: 90%; /* 行の高さのずれを詰める */
descent-override: 22%;
}
/* さらに、本フォントの到着自体を早めると切り替えが前倒しになる */
/* <link rel="preload" href="/f.woff2" as="font" type="font/woff2" crossorigin> */font-display: swap で不可視テキストを避けつつ、size-adjust や ascent-override で代替フォントと本フォントの寸法差をあらかじめ詰めておくと、差し替え時のずれが最小化されます。 さらに本フォントを <link rel="preload"> で先読みすれば、切り替え自体が前倒しになり、揺れる時間そのものが短くなります。
自分のサイトの CLS はどう確認しますか?
実ユーザーの値は Search Console の「ウェブに関する主な指標」で確認でき、これが合否に使われます。原因の特定には Chrome DevTools の Performance パネルが有効で、どの要素がいつずれたかを 1 つずつ追えます。ただし CLS は読み込みの速さや操作のタイミングで変動するため、1 回の計測で判断せず、実ユーザーの集計値を基準にします。
確認は「実測(フィールド)」と「原因特定(ラボ)」を役割分担させます。 合否に使われるのは実ユーザーの値のほうで、ラボはあくまで原因を突き止めるための道具です。
- Search Console の「ウェブに関する主な指標」 — 実ユーザーの集計値。ここが評価の本体
- Chrome DevTools の Performance パネル — どの要素がいつ・どれだけずれたかを 1 つずつ追える
- PageSpeed Insights — 実測値(CrUX)とラボ値を並べて見られる
なお本ツールは JavaScript を実行しないため、CLS を自前で測ることはできません。実測は PageSpeed Insights API に委ねており、 その考え方は Core Web Vitals — LCP・INP・CLS の改善 にまとめています。 一方で、CLS の主因であるサイズ未指定の画像は HTML から静的に検出できるため、 画像最適化の観点からは JavaScript の実行なしでも指摘が可能です。