実例に学ぶサイトスピード改善(6) 画像の寸法指定でガクッと動くページを防ぐ

CLSは「表示の速さ」とは別の指標で、ページ読み込み中にコンテンツが突然ずれる現象を数値化したものだ。画像にwidth/height属性を指定してアスペクト比をブラウザに教える、カルーセルの初期高さをCSSで確保するという2つのアプローチで、実在4サイトのCLSが最大89%改善するというシミュレーション結果を数値とともに紹介する。

writer K. Miyanagadate 2026.07.19 (Sun)read 5分cat サイトスピード改善, 技術解説

連載「実例に学ぶサイトスピード改善」

実在サイトの表示速度ボトルネックを取り上げるシリーズ。原因と対処法をシミュレーションの数値で示しながら解説する。事例の詳細は弊社の表示速度ボトルネック実例研究(vigilante)で公開している。

  1. LCP画像は最優先で読み込ませる
  2. 画像は次世代フォーマットに移行する
  3. テキストはGZIP/Brotliで圧縮する
  4. 重い日本語Webフォントが表示を遅らせる
  5. 外部CDNは速いとは限らない
  6. 画像の寸法指定でガクッと動くページを防ぐ(本記事)
  7. head内の同期スクリプトが描画を止める(近日公開)

ページがガクッと動く不快感の正体

ページが途中でガクッと動く経験は珍しくない。記事を読んでいたら文章が突然下に飛ぶ。ボタンを押しそうになったら別のリンクに差し変わって誤タップする。あの不快感を数値化したのが CLS(Cumulative Layout Shift) だ。

LCPやFCPが「コンテンツが表示されるまでの時間」を問うのに対して、CLSは「読み込み中にレイアウトがどれだけずれたか」を問う指標だ。表示が速くてもページがガタガタ動けばCLSは高い。CLSが低くてもLCPが遅いケースもある。両者は独立した軸で評価される。

もっとも、CLSは比較的対処しやすい指標でもある。Core Web VitalsがSEOの文脈で注目され始めた2021〜2022年ごろには、すでにCLS対策を終えていたサイトも多かった。HTMLとCSSを丁寧に書けば防げる確率が高いからだ。とはいえ丁寧に書いたつもりでも抜け落ちる箇所はある。

弊社の表示速度ボトルネック実例研究(vigilante)では、CLSを大きく押し上げる原因として2つのパターンを繰り返し観測している。ひとつは画像に width/height 属性が指定されていないこと。もうひとつはカルーセル(スライダー)の高さがJavaScript初期化前に確保されていないことだ。どちらもHTML/CSSの数行の変更で対処できる。


CLSとは何か

CLS(Cumulative Layout Shift)は、ページの読み込み中に発生したレイアウトのずれを累積的に計測したCore Web Vitalsの指標だ。Googleは0.1以下を「良好」、0.25以上を「改善が必要」と定義している。

レイアウトシフトとは、表示中のコンテンツが予期せず位置を変える現象だ。読んでいたテキストが突然スクロールして消える、タップしようとしたボタンが別の要素に差し変わって誤操作するといった体験がこれにあたる。ユーザーの意図しないところでページが動くため、可読性の妨害や誤タップにつながりうる。

この記事で扱うのは「ページを速く表示する」話ではなく「ページが安定して表示される」話だ。CLSを改善してもLCPが速くなるわけではないし、LCPを改善してもCLSが下がるわけでもない。

画像の読み込みでテキストが下にずれるレイアウトシフト(CLS)の概念図

なぜ画像でCLSが起きるのか

<img> 要素に widthheight を指定していない場合、ブラウザは画像の表示サイズを事前に知ることができない。HTMLを解析した時点では高さがゼロとして扱われ、画像のダウンロードが完了した瞬間に実際のサイズで描画される。この切り替わりが、周囲のテキストやボタンを一気に押しのける。

html
<!-- 高さを事前計算できないので画像読み込み完了時にずれが発生する -->
<img src="banner.jpg" alt="キャンペーンバナー">

<!-- width/heightを指定するとアスペクト比から空間が事前確保される -->
<img src="banner.jpg" alt="キャンペーンバナー" width="800" height="400">

width/height を指定するとブラウザがアスペクト比から表示領域を計算し、ダウンロード完了前から空間を確保しておく。これだけでレイアウトシフトは大幅に抑えられる。

CSSで aspect-ratio を指定する方法でも同じ効果が得られる。レスポンシブ対応で固定ピクセルを指定しにくい場合はこちらが有効だ。

css
/* aspect-ratioでアスペクト比を事前指定する代替手段 */
.logo-image {
  aspect-ratio: 200 / 80;
  width: 100%;
  height: auto;
}

なお width/height 属性を指定しつつCSSで width: 100%; height: auto; を適用しても問題ない。ブラウザはHTML属性からアスペクト比を計算して空間を確保し、CSSで実際のレイアウトサイズへスケールさせる仕組みだ。

カルーセルでCLSが起きる構造

カルーセル(スライダー)はJavaScriptで初期化される。HTML読み込み直後は全スライドが縦に積み重なって表示されることが多い。JavaScriptで1枚表示へ切り替わった瞬間、ページの高さが急変してレイアウトシフトを起こす。

この問題の根本は、JavaScript初期化前の状態が未定義のままになっていることだ。CSSで初期状態の高さをあらかじめ制限しておけば、初期化後の高さ変化を最小限に抑えられる。

css
/* JavaScript初期化前に1枚目だけ表示してシフトを抑える例(slick.jsの場合) */
.main-slider:not(.slick-initialized) .slide {
  display: none;
}
.main-slider:not(.slick-initialized) .slide:first-child {
  display: block;
}

ライブラリによって実装方法は異なるが、「JS初期化前に高さが未定義のコンテナができてしまう」という構造は共通している。スライダーコンテナに最小高さをCSSで指定する方法も有効な選択肢だ。

カルーセルのJS初期化前後で高さが急変し、レイアウトシフトが起きる

実例で確認するCLSの改善

弊社のボトルネック実例研究では、CLSに関連するこれらの問題を4サイトで観測した。各サイトの数値は、サードパーティタグの影響を除いたサイト固有のシミュレーション結果だ。タグを含む観測値とは若干異なる場合がある。

タマチャンショップ:CLS 0.447 → 0.047(シミュレーション)

タマチャンショップ トップページのスクリーンショット

宮崎県の自然食品ECタマチャンショップでは、lazysizesでlazyloadされる複数の画像(バナー、ナビアイコン、ロゴ等)の src 属性が空(src="")で width/height 属性も未指定の状態が観測された。Flickityスライダーについても、JavaScript初期化前にCSSで高さが確保されていなかった。これらが複合的に作用して、画像読み込み完了時に大きなレイアウトシフトが発生していた。

解消のシミュレーションは2段階で実施した。lazyload画像の src 属性にSVGプレースホルダーを設定し、正確な width/height 属性を付与してアスペクト比をブラウザに伝えた。あわせてFlickityスライダーにCSSで初期高さを確保した。

指標解消前解消後(シミュレーション)変化量
CLS0.4470.047-0.400(89%)
総合スコア7492+18

シミュレーションではCLSが0.447から0.047へ89%変化し、「良好」の基準値0.1を大きく下回る値に達した。詳細はタマチャンショップのボトルネック研究を参照してほしい。

富澤商店(TOMIZ):CLS 0.323 → 0.061(シミュレーション)

富澤商店オンラインショップ トップページのスクリーンショット

製菓・製パン材料のEC富澤商店オンラインショップでは、ページ内131個の <img> 要素のうち92個に width/height 属性が指定されていない状態が観測された。ブラウザが画像のアスペクト比を事前計算できないため、読み込み完了のたびに周囲のコンテンツがずれていた。

解消の方法はシンプルで、92個の <img> 要素に各画像の実寸に基づいた width/height 属性を追加するシミュレーションを実施した。

指標解消前解消後(シミュレーション)変化量
CLS0.3230.061-0.262
総合スコア8298+16

width/height 属性の追加だけでCLSが81%変化し、総合スコアも16ポイント上昇するというシミュレーション結果になった。基本的なHTML属性の有無がこれほど大きな影響を持っていたことを示す例だ。詳細は富澤商店のボトルネック研究にまとめている。

Billboard Japan:CLS 0.721 → 0.002(シミュレーション)

Billboard Japan トップページのスクリーンショット

音楽メディアのBillboard Japanでは、HTMLの74箇所すべての <img> 要素に width/height 属性が指定されていない状態が観測された。サードパーティタグ除去後の状態でCLSが0.721という極めて高い値を示しており、width/height 未指定が主因として特定された。

解消のシミュレーションでは、全74箇所の <img> 要素に width/height 属性を追加し、CSSで img { max-width: 100%; height: auto; } を併用することでレスポンシブデザインとの互換性を維持した。あわせてGoogle Fontsに font-display: swap を追加し、フォント由来のシフトの軽減も図った。

html
<!-- 変更前: ブラウザが高さを確保できない -->
<img src="/common/sys/img/specialbanner/1634/image_l_1.jpg" alt="">

<!-- 変更後: アスペクト比から空間が事前確保される -->
<img src="/common/sys/img/specialbanner/1634/image_l_1.jpg" alt="" width="1327" height="886">
指標解消前解消後(シミュレーション)変化量
CLS0.7210.002-0.719
総合スコア76100+24
LCP2.1秒1.4秒-0.7秒

シミュレーションではCLSが0.721から0.002へと事実上ゼロに近い値まで変化し、総合スコアは24ポイント上昇した。なお、LCP も副次的に0.7秒短縮されている。これは画像サイズの確保によって早期にレイアウトが安定し、レンダリングが効率化された結果だと思われる。詳細はBillboard Japanのボトルネック研究を参照してほしい。

ABAHOUSE ONLINE STORE:CLS 0.527 → 0.037(シミュレーション)

ABAHOUSE ONLINE STORE トップページのスクリーンショット

ファッション通販のABAHOUSE ONLINE STOREでは、CLSを押し上げる要因が2つ重なっていた。

ひとつはメインカルーセル(slick.js)のレイアウトシフトだ。JavaScript初期化前に全15スライドが縦に展開された状態で表示され、初期化後に1枚表示へ切り替わる際に大きなシフトが発生していた。CSSでカルーセルの初期状態の高さを制限し、slickが付与する .slick-initialized クラスの追加後に制限を解除することで対処した。

もうひとつは img 要素への width/height 属性の未指定だ。バナー画像やヘッダーロゴを含む8箇所への属性追加と、ブランドロゴ14画像へのCSSの aspect-ratio 指定で対処した。

ボトルネック解消前 CLS解消後 CLS(シミュレーション)変化量
カルーセルの高さ未確保0.5270.107-0.420
width/height属性未指定0.1070.037-0.070

2段階の対処を加えたシミュレーションで、CLSは0.527から0.037へと93%変化した。カルーセルのシフトが支配的で、画像属性はその残差を取り除いた形だ。総合スコアはカルーセル対処だけで79から97へ18ポイント上昇し、画像属性の追加でさらに100に到達した。詳細はABAHOUSE ONLINE STOREのボトルネック研究にまとめている。

自分のサイトで対処するには

CLSの改善は、原因の種類によって対処の方向が異なる。まず自サイトのCLSを計測してシフトの発生源を特定することが先決だ。

ステップ1:CLSを計測してシフト発生源を特定する

Chrome DevToolsの「Performance」タブでページを読み込むと、レイアウトシフトの発生タイミングと原因要素が記録される。「Experience」セクションに Layout Shift のイベントとして表示されるため、どの要素がシフトを引き起こしているかを確認できる。

Google Search ConsoleのCore Web Vitalsレポートも、フィールドデータとして実ユーザーのCLS傾向を把握するのに役立つ。CLSスコアが高い場合はまず発生源の特定から始めてほしい。

ステップ2:画像にwidth/heightを指定する

特定したシフトの原因が <img> 要素であれば、その要素に width/height 属性を追加する。CMSやECプラットフォームが自動生成するHTMLの場合は、テンプレートを修正するか、プラグインやオプションで属性を出力させる設定を確認したい。

CSSで width: 100%; height: auto; を適用するレスポンシブ対応と width/height 属性は共存できる。HTML属性でアスペクト比を伝えつつ、CSSで表示サイズをコントロールすればよい。

ステップ3:カルーセルの高さをCSSで事前確保する

シフトの原因がカルーセルやスライダーであれば、JavaScript初期化前の初期状態で高さをCSSで制限する方法を検討したい。ライブラリが初期化後に付与するクラスを使って制限を解除する方法と、コンテナに最小高さを指定してシフト幅を抑える方法のどちらかを取る。

どちらの場合も、ライブラリのバージョンアップや設定変更で初期化のタイミングや付与されるクラス名が変わることもある。修正後はDevToolsで実際のシフトが解消されたかを確認しておきたい。

まとめ

  • CLSはLCP/FCPとは別軸の指標。 表示が速くてもページがガタガタ動けばCLSは高い。この記事はレイアウトの安定性の話であり、表示速度の改善とは直接関係しない。
  • 画像の width/height 未指定はCLSの最もよくある原因のひとつ。 富澤商店では92個、Billboard Japanでは74個の <img> 要素に属性が設定されておらず、追加だけで16〜24ポイントの総合スコア改善というシミュレーション結果が得られた。
  • カルーセルはJS初期化前の高さ確保が要点。 ABAHOUSEではslick.jsの初期化前後のシフトがCLS 0.527の主因だった。CSSで初期状態を制御するシミュレーションで0.107まで変化した。
  • 複合要因が重なることもある。 タマチャンショップのように、lazyload画像の空間未確保とスライダーの高さ未確保が重なってCLS 0.447という値を示していた例もある。2つの対処を合わせたシミュレーションで0.047まで変化した。
  • 対処の難易度は低い。 丁寧なHTML/CSSコーディングで防げる確率が高く、すでに対応を終えているサイトも多い。コードの変更量は少なく、サーバー設定も不要だ。CLSが高い場合はまずDevToolsでシフトの発生源を確認し、width/height の有無とカルーセルの初期状態を確認してほしい。

自社サイトのCLSや他のボトルネックを体系的に調べたい場合は、弊社の表示速度ボトルネック研究 vigilante の事例が参考になる。より詳しい調査が必要な場合はアイデアマンズまでご相談いただきたい。