本文へスキップ
サイト総合診断

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 の判定基準
評価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-displaysize-adjust で寸法差を詰める

画像や動画のずれはどう防ぎますか?

画像・動画・iframe に width と height 属性を指定し、ブラウザに表示前から縦横比を伝えます。属性があれば、ダウンロードが終わる前に正しい大きさの場所が予約され、あとから画像が入っても既存の内容が動きません。CSS で幅を可変にする場合も属性は残し、height: auto を併用します。属性を使えない要素には aspect-ratio で比率を指定します。

画像・動画・iframe に場所を予約させる
<!-- 画像は 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-adjustascent-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 の実行なしでも指摘が可能です。

参考にした一次情報

関連する解説

自分のサイトは、実際どうなっているか

この記事で説明した項目は、すべて無料の診断ツールで実測できます。URL を入れるだけ・登録不要です。

無料で診断する