gazou-compressor.jp

INP時代の画像遅延読み込み:lazy/priority/fetchpriority/sizesの最適解

画像の遅延読み込みはネットワークを節約しますが、やり方を誤るとINP(入力応答)LCPを悪化させます。鍵は“ヒーローだけは即時”“折り返し以降は遅延”、 そして“描画幅に合った配信”の3点です。本記事は最短で運用に落とせるルールと実装を提示します。

先に結論(最短フロー)
  • LCP候補(ヒーロー)はlazy禁止fetchpriority="high"preload
  • 折り返し以降は loading="lazy"。IntersectionObserverで1〜1.5画面先を先読み。
  • srcset/sizes実表示幅に一致(関連: srcset/sizes)。
  • すべての <img>width/height を指定し、 CLSゼロ設計 と両立。

要点(TL;DR)

1. なぜ“lazyだけ”ではダメなのか

重要画像まで lazy にすると、ユーザー操作直後のペイントが遅れINPの悪化に繋がります。 逆に何でも eager にするとネットワーク飽和でLCP悪化。優先度の切り分けが肝心です。

2. 最短フロー(実務)

  1. ヒーロー(LCP)を特定し、preload + fetchpriority="high" を付与。
  2. 折り返し以降の画像は loading="lazy"。IOで1〜1.5画面先の先読み。
  3. srcset/sizes を描画幅に合わせ、過大DLを阻止。
  4. 全画像に width/height を必ず入れる(CLSゼロ運用)。

3. 実装レシピ(コピペOK)

3.1 ヒーロー(LCP)

// HTML<!-- ヒーロー(LCP候補)は lazy禁止。fetchpriority="high" + 適切な sizes -->
<link
  rel="preload"
  as="image"
  href="/hero-1200.avif"
  imagesrcset="/hero-800.avif 800w, /hero-1200.avif 1200w, /hero-1600.avif 1600w"
  imagesizes="(min-width: 1024px) 1000px, 92vw"
/>
<img
  src="/hero-1200.avif"
  srcset="/hero-800.avif 800w, /hero-1200.avif 1200w, /hero-1600.avif 1600w"
  sizes="(min-width: 1024px) 1000px, 92vw"
  width="1600" height="900"
  alt="ヒーロー"
  fetchpriority="high"
  decoding="async"
/>

3.2 カード一覧(lazy)

// HTML<!-- 折り返し以降のカード画像は lazy + 適切な sizes -->
<img
  src="/thumb-640.webp"
  srcset="/thumb-320.webp 320w, /thumb-480.webp 480w, /thumb-640.webp 640w"
  sizes="(min-width: 1024px) 320px, (min-width: 640px) 33vw, 45vw"
  width="640" height="400"
  alt="カード"
  loading="lazy"
  decoding="async"
/>

3.3 IntersectionObserverで先読み幅調整

// JavaScript// IntersectionObserverで「スクロール1〜1.5画面先」を先読み
const io = new IntersectionObserver((entries) => {
  for (const e of entries) {
    if (e.isIntersecting) {
      const img = e.target as HTMLImageElement;
      // data- 属性から本来のsrc/srcsetに差し替え
      if (img.dataset.src) img.src = img.dataset.src;
      if (img.dataset.srcset) img.srcset = img.dataset.srcset;
      io.unobserve(img);
    }
  }
}, { rootMargin: "150% 0px" }); // 1.5画面先で事前ロード

document.querySelectorAll("img[data-src]").forEach((el) => io.observe(el));

3.4 content-visibilityで描画負荷を削減

// CSS/* 画像が多い長文記事に:非表示領域のレイアウト計算をスキップ */
.article-section {
  content-visibility: auto; /* ビューポート外は描画を遅延 */
  contain-intrinsic-size: 1px 600px; /* 予測高さでレイアウトを安定 */
}

3.5 優先度ルール(ミニガイド)

// Guide// 画像優先度の判断(最小ルール)
/*
  - LCP候補(ビューポート内の最大画像): fetchpriority="high"(lazy禁止)
  - ファーストビューの補助画像: fetchpriority="low" か none(状況次第)
  - 折り返し以降: loading="lazy"(IOで先読み幅を調整)
  - すべての <img> に width/height(CLS対策)
  - srcset/sizes は実表示幅に一致(過大DLの回避)
*/

4. 応用とハマりどころ

5. 公開前チェック

6. まとめ

“ヒーローは即時・それ以外は遅延・描画幅に合わせる”——この3点をテンプレ化すれば、INP/LCP/CLSを同時に改善できます。 実装後は /compare /compressor で画質・容量を検証し、安定運用に移行しましょう。

FAQ(よくある質問)

画像形式の基本方針は?(写真/スクショ/透過)
写真は AVIF / WebP(画質80–85%目安)、UIやスクショはPNG / WebP Lossless、単色ロゴはSVGが基本です。 実装の詳細は srcset/sizes設計ガイド スクショ最適化 を参照してください。
圧縮しても画質を落とさないコツは?
実表示幅に合わせたリサイズ → 過大ダウンロードを防ぎ、srcset/sizes を 実描画幅に一致させます。画質は写真で 80–85% を起点に、ノイズやエッジを目視確認。 仕上げは /compare で Before/After を見比べるのがおすすめです。
CLSを悪化させない画像の置き方は?
すべての画像に width/height(または親に aspect-ratio)を与え、広告・埋め込みは 予約サイズを先に確保します。詳しくは CLSゼロ設計ガイド を参照。

公開:2025-08-31

gazou-compressor.jp 編集部

画像圧縮・変換・背景除去などの実践テクニックと、Webで“速く・軽く・崩さない”ためのノウハウを発信しています。

関連記事