ブログに戻る
テクノロジー

2026年 Web サイトの画像が遅い?エンジニア必携 8 項目 パフォーマンス最適化

公開日16 min read
共有

画像はWebパフォーマンスの最大のボトルネック

技術的な観点から見ると、画像は現代のWebページの総転送量の圧倒的な割合を占めています。HTTP Archive 2025年12月の統計データによると、デスクトップ版Webページの中央値の総サイズは約2,312 KBで、そのうち画像は約1,026 KBと全体の**約44.4%**を占めています。モバイル版ではこの比率はさらに高く、画像が総転送量の約47%を占めます。

これが意味するのは一つ:Webサイトで1つだけ最適化するなら、画像を選べば間違いない。

さらに重要なのは、画像がGoogleのCore Web Vitals指標、特にLCP(Largest Contentful Paint)に直接影響することです。GoogleのCrUXレポートによると、70%以上のWebページのLCP要素は画像または背景画像を持つブロックです。LCPが2.5秒を超えると「改善が必要」、4秒を超えると「不良」と判定され、SEOランキングに直接影響します。

以下では、アーキテクチャの観点から画像最適化の各工程を一つずつ分解していきます。

実際に踏んだ地雷:LCP が 1.8s から 6.2s に跳ね上がった話

先に結論を言います。正直なところ、去年あるクライアント案件で LCP が緑ゾーン(1.8s)から赤ゾーン(6.2s)に暴走しました。触ったのはトップページの hero 画像 1 枚だけ。最初は JS bundle が爆発したと思い込み、3日デバッグして原因判明——新しいデザイナーが 4.5MB の 1920×1080 PNG をトップに直で置いただけ。圧縮なし、loading 属性なし、fetchpriority なし、CDN も経由していない。ぶっちゃけこの 1 枚で LCP が崩壊しました。

その後 3 つ対処したら LCP は 1.9s まで戻りました:

  1. PNG を WebP に変換し 180KB まで圧縮(96% 削減)
  2. fetchpriority="high" と <link rel="preload"> を追加
  3. 画像を Cloudflare R2 + Transform Rules に載せて AVIF fallback を自動化

この落とし穴は本当に多くの人が踏んでいます。まじで、トップページの hero 画像こそ LCP の急所で、どこか 1 工程ミスっただけで Core Web Vitals のレポートが全部赤くなります。以下の各章はドキュメントの写しではなく、こういう案件から抽出したものです。

Lazy Loading:ビューポート外の画像を遅延読み込み

ネイティブHTML方式

最もシンプルな方法は、ブラウザネイティブの loading="lazy" 属性を使用することです:

<img src="photo.webp" loading="lazy" alt="サンプル画像" width="800" height="600">

仕組みとしては、ブラウザは画像がビューポートの近くに入った時点でHTTPリクエストを発行します。Chromeの実装では、ビューポートから約1250px(デスクトップ)または2500px(低速ネットワーク)の距離で読み込みを開始し、ユーザーが画像の位置までスクロールした時にはすでに読み込みが完了しているようにしています。

注意:ファーストビューに表示される画像(Above the Fold)にはlazy loadingを設定すべきではありません。LCPが遅延します。ファーストビューの画像は loading="eager"(デフォルト値)を使用し、fetchpriority="high" を追加して優先度を上げましょう。

JavaScript方式:Intersection Observer

より細かい制御が必要な場合は、Intersection Observer APIを使用できます:

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      observer.unobserve(img);
    }
  });
}, { rootMargin: '200px' });

document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));

この方式の利点は、トリガー距離(rootMargin)のカスタマイズ、フェードインアニメーションとの連携、読み込み前の低解像度プレースホルダー画像(LQIP)の表示が可能なことです。

2つの方式の比較

比較項目 ネイティブ loading="lazy" Intersection Observer
実装の複雑さ 極低(属性1つ) 中程度(JS記述が必要)
ブラウザ対応 95%+(2026年) 97%+
トリガー距離の制御 不可(ブラウザが決定) 可能(rootMargin)
LQIPプレースホルダー 非対応 対応
SEOフレンドリー はい(ブラウザネイティブ) noscriptのフォールバック確認が必要
ファーストビュー誤用リスク あり(手動除外が必要) プログラマティックに除外可能

推奨戦略:ほとんどの場面ではネイティブ方式で十分。LQIPや精密な制御が必要な場合のみIntersection Observerを使用。

Responsive Images:デバイスに必要なサイズだけをダウンロード

幅3000pxのヒーロー画像が、スマートフォンでは750pxの幅しか必要ありません。responsive imagesを設定しないと、モバイルユーザーは4倍の大きさの画像を無駄にダウンロードすることになります。

srcset + sizes の実装

<img
  srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w, hero-1600.webp 1600w"
  sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
  src="hero-800.webp"
  alt="トップページバナー"
>

ブラウザはデバイスのビューポート幅とピクセル密度に基づいて、srcsetから最適な画像を選択します。sizes は、異なるブレークポイントでこの画像がどのくらいの幅を占めるかをブラウザに伝え、より正確な選択を可能にします。

<picture> 要素:フォーマットとアートディレクションの制御

<picture>
  <source srcset="hero.avif" type="image/avif">
  <source srcset="hero.webp" type="image/webp">
  <img src="hero.jpg" alt="トップページバナー">
</picture>

<picture> を使うと、異なるブラウザに異なるフォーマットを提供でき、圧縮率の最も高いフォーマットを優先的に使用し、互換フォーマットに自動フォールバックします。

画像フォーマットの選択戦略

フォーマットの選択はファイルサイズと画質に直接影響します。以下は実測データに基づく比較です(テスト条件:同一の1920x1080写真、同等の視覚品質):

フォーマット 典型的なファイルサイズ ブラウザ対応 透過 アニメーション 適用場面
JPEG 基準 100% 100% 非対応 非対応 写真(最大互換性)
WebP JPEGの約70% 97%+ 対応 対応 写真とグラフィック(推奨デフォルト)
AVIF JPEGの約50% 92%+ 対応 対応 写真(最高圧縮率)
PNG JPEGの300-500% 100% 対応 非対応 透過が必要なグラフィック
SVG 極小(ベクター) 100% 対応 対応 アイコン、ロゴ、チャート

推奨戦略:AVIF → WebP → JPEGのプログレッシブデグラデーションを優先的に提供。<picture> 要素でブラウザに最適なフォーマットを自動選択させましょう。

CDNとキャッシュ戦略

CDNの核心的な価値

日本のサーバーからアメリカのユーザーに画像を転送する場合、物理的距離は約10,000km、光ファイバー中の光速伝播遅延だけで約33ms(片道)。TCP handshake、TLS交換、HTTPリクエスト/レスポンスを加えると、1枚の画像のTTFB(Time To First Byte)は200msを超えることがあります。

CDNはグローバルなエッジノードで画像をキャッシュし、ユーザーが最も近いノードからリソースを取得できるようにします。優れたCDNならTTFBを200ms超から20-50msに削減できます。

キャッシュヘッダーの設定

Cache-Control: public, max-age=31536000, immutable

画像は通常変更されないため、1年のキャッシュ期間と immutable フラグを設定し、ブラウザに再検証不要であることを伝えます。画像の更新が必要な場合は、ファイル名の変更(ハッシュの付加)で強制的にキャッシュを無効化します。

画像CDNサービス

Cloudflare Images、Imgix、Cloudinaryなどの画像CDNサービスは、基本的なCDN配信に加えて以下の機能を提供します:

  • リアルタイムフォーマット変換(Acceptヘッダーに基づいてAVIF/WebP/JPEGを自動選択)
  • リアルタイムリサイズ(URLパラメータで幅・高さを指定)
  • 自動品質最適化(ネットワーク速度に応じて圧縮率を調整)

画像圧縮パイプライン

技術アーキテクチャの観点から、完全な画像圧縮パイプラインには以下の工程が含まれるべきです:

  1. アップロード時の圧縮:Sharp(Node.js)やPillow(Python)でサーバーサイドで圧縮
  2. マルチサイズ生成:各画像に3-5のサイズバリアント(400w、800w、1200w、1600w、原寸)を生成
  3. マルチフォーマット変換:各サイズにAVIF、WebP、JPEGの3フォーマットを生成
  4. 品質パラメータ調整:JPEG quality 75-85、WebP quality 75-80、AVIF quality 60-70
  5. メタデータ除去:EXIFデータを削除してファイルサイズを削減(プライバシー保護にもなる)

1920x1080の写真を例にすると、完全なパイプラインを経た後、モバイルユーザーが実際にダウンロードするのは400wのAVIF画像で、ファイルサイズは元の2MBから約30KBに、**98.5%**の転送量削減となります。

Core Web Vitalsへの影響と最適化目標

LCP(Largest Contentful Paint)

LCPは最大の可視要素の描画時間を計測します。画像がLCP要素となるページの場合:

  • 良好:≤ 2.5秒
  • 改善が必要:2.5 - 4秒
  • 不良:> 4秒

ファーストビュー画像の具体的な最適化手法:

  1. fetchpriority="high" でファーストビュー画像のダウンロード優先度を上げる
  2. <link rel="preload"> でLCP画像をプリロード
  3. ファーストビュー画像にlazy loadingを使用しない
  4. ファーストビュー画像のCDNキャッシュヒット率を確保

CLS(Cumulative Layout Shift)

画像の読み込み時にスペースが確保されていないと、レイアウトのずれが発生します。解決法はシンプルです:<img> タグに必ず width と height 属性を指定し、画像の読み込み前にブラウザが正しいアスペクト比を計算できるようにします。

<img src="photo.webp" width="800" height="600" alt="サンプル">

画像パフォーマンス最適化チェックリスト

公開前に1つずつ確認しましょう:

  • ファーストビュー画像に fetchpriority="high" を設定、非ファーストビューに loading="lazy" を設定
  • すべての <img> タグに width と height 属性がある
  • <picture> でAVIF/WebP/JPEGのプログレッシブデグラデーションを提供
  • srcset + sizes でマルチサイズバリアントを提供
  • 画像が圧縮済み(JPEG quality 75-85、WebP quality 75-80)
  • CDNが有効、キャッシュヘッダーが正しく設定(max-age=31536000, immutable)
  • EXIFメタデータが除去済み
  • LCP画像を <link rel="preload"> でプリロード済み
  • PageSpeed InsightsでLCP ≤ 2.5秒

画像ホスティングサービスの役割

完全な画像圧縮パイプラインとCDNアーキテクチャを自前で構築したくない場合、専門の画像ホスティングサービスを利用するのは実用的な選択肢です。

lpic.cc を例にすると、登録不要の画像アップロード、CDNによるグローバル配信、パスワード保護機能を提供しています。ブログ執筆者や小規模サイトにとって、画像インフラの自社構築コストを省けます。ただし、lpic.ccは現在API連携やリアルタイムリサイズ機能を提供していないため、プロジェクトでプログラマティックなバッチアップロードや動的クロップが必要な場合は、Cloudinary、Imgixなどの専門画像CDNサービスとの併用が必要になるかもしれません。

よくある質問 FAQ

Q1:Lazy loadingはSEOに影響する?

影響しません。Googleのクローラー(Googlebot)はJavaScriptを実行しスクロールをシミュレートするため、loading="lazy" を使用した画像も正しくインデックスされます。ただし、カスタムJavaScriptのlazy loading方式を使用する場合は、<noscript> タグをフォールバックとして追加し、検索エンジンが画像URLを取得できるようにすることをお勧めします。

Q2:WebPとAVIF、どちらを優先すべき?

圧縮率ではAVIFが優位(JPEGより約50%小さい)ですが、AVIFのエンコード速度は遅く、リアルタイム変換のシーンには不向きです。推奨戦略は <picture> で両方を提供し、ブラウザに自動選択させること。1つだけ選ぶならWebPの方がブラウザ対応率が高く(97% vs 92%)、より安全な選択です。

Q3:画像CDNにお金をかける価値はある?

トラフィック規模によります。月間10万PV以下なら、Cloudflareの無料プラン(基本CDN付き)で通常十分です。それ以上の規模では、ImgixやCloudinaryなどの専門画像CDNの自動フォーマット変換やリサイズ機能で帯域幅コストを大幅に削減でき、長期的にはむしろコスト削減になります。

Q4:画像圧縮で画質は劣化する?

非可逆圧縮は必ず画質に影響しますが、適切な品質パラメータ(JPEG 75-85、WebP 75-80)であれば人間の目にはほぼ違いがわかりません。SSIM(構造類似性指標)で定量的に評価するのがお勧めです:SSIM > 0.95であれば、ほとんどのユーザーは圧縮前後の違いを区別できません。

Q5:サイトですでにCDNを使っているが、画像最適化もまだ必要?

必要です。CDNは「転送距離」の問題しか解決せず、「転送量」の問題は解決しません。最適化されていない5MBの画像は、CDNの最寄りのノードから転送されても5MBの帯域幅が必要です。フォーマット変換、サイズ適応、圧縮などの最適化手段で転送量を80-95%削減でき、単にCDNを使うだけよりはるかに大きな効果があります。

参考資料

#Webパフォーマンス#画像最適化#lazy loading#responsive images#CDN#Core Web Vitals
H

著者

Harvey Zhang

共同創業者・CTO

バックエンドエンジニア出身。システムアーキテクチャの観点から画像ホスティングサービスの技術実装を深く解説します。