Core Web Vitals と画像最適化の関係 - LCP, CLS, INP を改善する実践手法
Core Web Vitals と画像の関係 - なぜ画像がスコアを左右するのか
Core Web Vitals は Google が定義する Web ページのユーザー体験指標で、2021 年からランキングシグナルとして使用されています。3 つの指標 (LCP, CLS, INP) のうち、LCP と CLS は画像の最適化状態に直接的かつ大きな影響を受けます。HTTP Archive のデータによると、Web ページの総転送量の約 50% を画像が占めており、画像最適化は Web パフォーマンス改善の最大のレバレッジポイントです。
各指標と画像の関係:
- LCP (Largest Contentful Paint): ビューポート内で最も大きな要素が描画されるまでの時間。多くのページでヒーロー画像やメインビジュアルが LCP 要素となるため、画像の読み込み速度が LCP を直接決定します。目標値: 2.5 秒以内
- CLS (Cumulative Layout Shift): ページ読み込み中に発生するレイアウトのずれの累積量。画像の寸法が事前に確保されていない場合、画像読み込み完了時にレイアウトが大きくずれます。目標値: 0.1 以下
- INP (Interaction to Next Paint): ユーザー操作から次の描画までの応答時間。画像のデコード処理がメインスレッドをブロックすると、操作への応答が遅延します。目標値: 200ms 以内
Google の PageSpeed Insights データによると、LCP が「不良」と判定されるページの約 72% で、LCP 要素が画像であることが報告されています。つまり、画像の最適化だけで大多数のページの LCP を改善できる可能性があります。
LCP の改善 - 画像読み込みを高速化する 5 つの戦略
LCP 要素が画像である場合、その画像がブラウザに到達し、デコードされ、描画されるまでの全プロセスを最適化する必要があります。LCP は「リソース読み込み時間」「レンダリング遅延」「サーバー応答時間」「クライアント処理時間」の合計で決まります。
戦略 1: プリロードによる早期取得
<link rel="preload" as="image" href="hero.webp">で LCP 画像を HTML パース段階で即座にフェッチ開始します- レスポンシブ画像の場合:
<link rel="preload" as="image" imagesrcset="..." imagesizes="..."> - プリロードにより、CSS や JS の解析を待たずに画像取得が開始され、LCP を 200-500ms 改善できます
戦略 2: 最適なフォーマットとサイズ
- WebP は JPEG 比で 25-35% 小さく、AVIF は 40-50% 小さい。フォーマット変更だけで転送量を大幅削減
<picture>要素で AVIF → WebP → JPEG のフォールバックチェーンを構築- ビューポート幅に合わせた適切なサイズの画像を
srcsetとsizesで提供
戦略 3: CDN とキャッシュの活用
- CloudFront や Cloudflare でエッジキャッシュし、物理的な距離による遅延を最小化
Cache-Control: public, max-age=31536000, immutableで長期キャッシュを設定- 画像 URL にコンテンツハッシュを含めてキャッシュバスティングを実現
戦略 4: fetchpriority 属性
<img fetchpriority="high">で LCP 画像の取得優先度を明示的に引き上げます- ブラウザのリソース優先度スケジューラに対して、この画像が最重要であることを伝えます
戦略 5: サーバーサイドレンダリング (SSR)
- LCP 画像の URL を HTML に直接含めることで、JavaScript の実行を待たずに画像取得を開始できます
- SPA で画像 URL が JS 実行後に決定される場合、LCP が大幅に悪化します
CLS の防止 - 画像によるレイアウトシフトをゼロにする
CLS (Cumulative Layout Shift) は、ページ読み込み中にコンテンツが予期せず移動する現象を数値化した指標です。画像は CLS の最大の原因の一つであり、適切な対策を施さないと、画像読み込み完了時にページ全体が大きくジャンプします。
画像が CLS を引き起こすメカニズム:
- ブラウザは画像の読み込みが完了するまで、その画像の寸法を知りません
- 寸法が不明な画像は高さ 0 として扱われ、読み込み完了時に実際の高さ分だけ後続コンテンツが押し下げられます
- この「押し下げ」がレイアウトシフトとして計測され、CLS スコアを悪化させます
CLS を防止する実装パターン:
- width/height 属性の明示:
<img width="800" height="600">を指定すると、ブラウザは画像読み込み前にアスペクト比を計算し、適切なスペースを確保します。CSS でwidth: 100%; height: auto;と組み合わせることで、レスポンシブかつ CLS ゼロを実現 - CSS aspect-ratio:
img { aspect-ratio: 4/3; width: 100%; }で明示的にアスペクト比を指定。width/height 属性がない場合のフォールバックとして有効 - コンテナによるスペース確保: 画像を囲むコンテナに固定のアスペクト比を設定し、画像は
object-fit: coverで表示
遅延読み込み画像の CLS 対策:
loading="lazy"を使用する画像にも必ず width/height を指定する- プレースホルダー (LQIP: Low Quality Image Placeholder) を表示し、本画像読み込み時のシフトを防止
- Intersection Observer で画像が表示領域に近づいた時点で読み込みを開始し、表示時には既に読み込み完了している状態を目指す
INP と画像デコード - メインスレッドのブロックを回避する
INP (Interaction to Next Paint) は 2024 年 3 月に FID (First Input Delay) に代わって Core Web Vitals に採用された新指標です。ユーザーの操作 (クリック、タップ、キー入力) から次の描画更新までの時間を測定し、ページ全体のインタラクティブ性を評価します。画像のデコード処理がメインスレッドを長時間ブロックすると、INP が悪化します。
画像デコードが INP に影響するケース:
- 大きな画像の同期デコード: 4,000 × 3,000 px の JPEG をデコードするのに 50-100ms かかる場合があり、この間メインスレッドがブロックされます
- スクロール時の大量デコード: 画像ギャラリーで一度に多数の画像がビューポートに入ると、デコード処理が集中してフレームドロップが発生します
- 画像切り替えアニメーション: カルーセルやライトボックスで大きな画像を切り替える際、デコード待ちで操作が固まることがあります
INP 改善のための画像デコード最適化:
- decode() メソッド:
img.decode().then(() => container.appendChild(img))で非同期デコードを行い、デコード完了後に DOM に追加します。メインスレッドのブロックを回避できます - content-visibility: auto: ビューポート外の画像コンテナに適用すると、ブラウザはレンダリングを遅延させ、スクロール時の処理負荷を分散します
- 適切なサイズの提供: 表示サイズより大きな画像を読み込まない。2x 以上のオーバーサンプリングはデコード時間を無駄に増加させます
- Web Worker でのデコード: OffscreenCanvas を使用して Web Worker 内で画像をデコードし、メインスレッドを完全に解放する高度なテクニック
画像の遅延読み込み戦略 - loading 属性と Intersection Observer
遅延読み込み (Lazy Loading) は、ビューポート外の画像の読み込みを遅延させ、初期表示に必要なリソースを優先的に取得する手法です。適切に実装すれば LCP を改善しつつ、ページ全体の転送量を削減できます。ただし、誤った実装は逆に LCP を悪化させるリスクがあります。
ネイティブ遅延読み込み (loading="lazy"):
- HTML 属性だけで実装可能。JavaScript 不要で最もシンプル
- ブラウザが自動的にビューポートからの距離を判定し、適切なタイミングで読み込みを開始
- Chrome ではビューポートから約 1,250 px (高速回線) または 2,500 px (低速回線) 手前で読み込みを開始
- 重要: LCP 要素には
loading="lazy"を絶対に設定しない。LCP 画像の読み込みが遅延され、スコアが大幅に悪化します
Intersection Observer による高度な制御:
rootMargin: '200px'でビューポートの 200px 手前から読み込みを開始するなど、閾値を細かく制御可能- 画像の読み込み状態に応じたアニメーション (フェードイン) を実装可能
- 読み込み優先度をカスタムロジックで制御 (例: 画面中央に近い画像を優先)
遅延読み込みのベストプラクティス:
- ファーストビュー (Above the fold) の画像には
loading="eager"(デフォルト) +fetchpriority="high"を設定 - ファーストビュー外の画像に
loading="lazy"を設定 - 画像数が多いページ (20 枚以上) では遅延読み込みの効果が顕著。初期転送量を 60-80% 削減可能
- プレースホルダーとして LQIP (20x20px のぼかし画像) や dominant color (単色背景) を表示し、UX を維持
実測データに基づく改善の優先順位と効果測定
画像最適化の施策は多岐にわたりますが、すべてを同時に実施する必要はありません。実測データに基づいて最も効果の高い施策から順に実施し、各施策の効果を定量的に測定することが重要です。
改善効果の大きい順 (一般的なケース):
- 1. LCP 画像のプリロード: 効果 200-500ms 改善。実装コスト: 低 (HTML 1 行追加)
- 2. 次世代フォーマット (WebP/AVIF) への変換: 効果 30-50% ファイルサイズ削減。実装コスト: 中 (ビルドパイプライン変更)
- 3. 適切なサイズの画像提供 (srcset): 効果 40-70% 転送量削減 (モバイル)。実装コスト: 中
- 4. width/height 属性の追加: 効果 CLS 0.1-0.3 改善。実装コスト: 低
- 5. 遅延読み込みの適用: 効果 初期転送量 50-80% 削減。実装コスト: 低
- 6. CDN キャッシュの最適化: 効果 TTFB 100-300ms 改善。実装コスト: 低-中
効果測定の方法:
- Chrome DevTools Lighthouse: ローカルでの簡易測定。ラボデータのため実際のユーザー体験とは異なる場合がある
- PageSpeed Insights: CrUX (Chrome User Experience Report) のフィールドデータを表示。実際のユーザーの 75 パーセンタイル値
- Web Vitals JavaScript ライブラリ:
import {onLCP, onCLS, onINP} from 'web-vitals'で実ユーザーの指標を収集し、Google Analytics 4 に送信 - Search Console: Core Web Vitals レポートでページグループごとの合否状況を確認。ランキングへの影響を把握
A/B テストによる効果検証: 施策適用前後で同一ページの CrUX データを 28 日間比較し、統計的に有意な改善が得られたかを確認します。