gazou-compressor.jp

INP時代の画像最適化 — decoding='async'・preload・lazyの最適バランス

2024年以降、Core Web Vitals は「INP(Interaction to Next Paint)」が主役になりました。画像は 表示 の品質だけでなく操作応答 にも影響します。本稿は、INP を悪化させない画像読み込み戦略を、値の目安・実装テンプレ・検証手順まで一気通貫でまとめた実務ガイドです。

公開:  最終更新:

TL;DR(先に要点)

  • LCP候補の画像preload or Next/Image の priority fetchpriority="high" を併用。decoding="sync" は使わない(メインスレッドを止めやすい)。
  • 折りたたみ下loading="lazy" + decoding="async"lazy + sync はアンチパターン。
  • インタラクション直前に使う画像は img.decode() で先行デコード(モーダルの原寸表示など)。
  • 必ず width/heightaspect-ratio を指定(CLS回避は INP にも好影響)。

なぜ画像が INP を悪化させるのか

ユーザーがタップ/クリックしてから「次のペイント」までの時間が INP です。操作直後に画像の同期デコードや大きなリフローが発生すると、メインスレッドが占有され INP が悪化します。 遅延読み込み済みの画像でも、decoding が同期だったり、sizes 不備で巨大画像を読み込むと イベント処理と競合します。

How:INPに効く画像読み込みテンプレ

1) LCP画像(ヒーロー)のテンプレ

<!-- HTML直書き -->
<link rel="preload" as="image" href="/hero.avif"
      imagesrcset="/hero.avif 1x, /hero@2x.avif 2x"
      fetchpriority="high">
<img src="/hero.avif" width="1600" height="900" decoding="async" alt="製品ヒーロー">

<!-- Next/Image -->
<Image
  src="/hero.avif"
  alt="製品ヒーロー"
  width={1600} height={900}
  priority
  fetchPriority="high"
/>
  • 元画像の実寸を width/height に指定し、レイアウトを先に確定。
  • decoding="async" でメインスレッド占有を避ける。

2) 折りたたみ下のギャラリー

<img
  src="/thumb.webp"
  width="480" height="320"
  loading="lazy" decoding="async"
  alt="サムネイル">

loading="lazy"decoding="async" とセットで。sizes を合わせると余計な大画像を避けられます。

3) モーダルの原寸を「先にデコード」

// 操作の ~300ms 以上前に呼ぶのが目安
const large = new Image();
large.src = "/product@2x.avif";
await large.decode();     // 非同期デコードを先行
openModal(large);

4) レスポンシブの鉄則(過大ダウンロード防止)

<img
  src="/hero-1600.avif"
  srcset="/hero-800.avif 800w, /hero-1200.avif 1200w, /hero-1600.avif 1600w"
  sizes="(min-width: 1024px) 1000px, 92vw"
  width="1600" height="900"
  decoding="async" fetchpriority="high" alt="">

sizes は「レイアウト上の見込み幅」。詳しくは レスポンシブ画像の最適化 を参照。

状況別ポリシー(保存版)

状況読み込みdecoding優先度備考
LCP候補preload / priorityasyncfetchpriority=high幅は実寸、sizesを明示
ファーストビュー内通常asyncsrcset/sizesで最適化
折りたたみ下lazyasyncIntersectionObserver相当
操作直前に必要通常JSでdecode()先行

計測と検証(DevTools手順)

  1. Performance パネルで Interaction(緑)を録画。長いタスク(>50ms)と Image Decode の重なりを確認。
  2. Network で LCP 画像が Priority: High か確認。HTTP/2 なら「最初期」に流れているか。
  3. Elements で LCP 画像に width/height or aspect-ratio があるか確認(CLS対策)。
  4. web-vitals ライブラリで INP をログ収集し、デプロイ前後の差分を比較。

まとめ

画像最適化は「軽さ」だけでは不十分です。いつ・どうデコードさせるかまで設計し、INP を守りながら視覚品質を両立しましょう。本稿のテンプレを CI やコンポーネントに仕込めば、チーム全体の再現性が上がります。

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

関連記事