Webページの表示速度を左右する最大の要因は画像です。HTTP Archiveのデータによると、Webページの総転送量のうち画像が占める割合は約40〜50%に達します(出典: HTTP Archive)。Nuxt 3で構築したサイトでこの課題に対処するには、公式モジュール @nuxt/image が最も効率的な選択肢です。
@nuxt/image とは
@nuxt/image は、Nuxt 3公式の画像最適化モジュールです。HTMLの <img> タグや <picture> タグを置き換える <NuxtImg> / <NuxtPicture> コンポーネントを提供し、以下の処理を自動化します。
- フォーマット変換: WebP・AVIFなど次世代フォーマットへの自動変換
- レスポンシブ対応: 画面サイズに応じた
srcsetとsizesの自動生成 - 遅延読み込み:
loading="lazy"によるビューポート外画像の遅延ロード - プリロード制御: LCP画像への
fetchpriority="high"付与とプリロード設定 - プロバイダー連携: IPX(セルフホスト)、Cloudinary、imgix、Vercelなど20以上のサービスに対応
インストールと初期設定
パッケージの追加
# 自動セットアップ(推奨)
npx nuxt module add image
# 手動インストール
npm install @nuxt/image
手動インストールの場合は nuxt.config.ts にモジュールを登録します。
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxt/image'],
image: {
// 画像オプション
}
})
基本的な設定例
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxt/image'],
image: {
quality: 80,
format: ['webp'],
screens: {
xs: 320,
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
'2xl': 1536,
},
domains: ['example.com'],
}
})
quality はデフォルト80で、全画像に適用される品質値です。format は <NuxtPicture> 使用時の優先フォーマットを配列で指定します。screens はTailwind CSSと同じブレークポイント命名規則に準拠しており、sizes 属性で sm:50vw のように参照できます。
NuxtImg と NuxtPicture の使い分け
@nuxt/image は2つのコンポーネントを提供しています。
NuxtImg
HTMLの <img> タグを置き換えるコンポーネントです。単一フォーマットの画像配信に適しています。
<template>
<NuxtImg
src="/images/hero.jpg"
alt="ヒーロー画像"
width="1200"
height="630"
sizes="100vw md:80vw lg:1200px"
quality="80"
format="webp"
loading="lazy"
/>
</template>
出力されるHTMLには、指定した sizes に応じた srcset が自動生成されます。
NuxtPicture
HTMLの <picture> タグを生成し、複数フォーマットの出し分けに対応します。ブラウザのサポート状況に応じてAVIF → WebP → JPEGの順にフォールバックさせたい場合に使用します。
<template>
<NuxtPicture
src="/images/product.jpg"
alt="製品写真"
width="800"
height="600"
sizes="100vw sm:50vw lg:400px"
format="avif,webp"
/>
</template>
選択基準の早見表
| 条件 | 推奨コンポーネント |
|---|---|
| WebPのみで配信 | <NuxtImg format="webp"> |
| AVIF + WebP + JPEGのフォールバック | <NuxtPicture> |
| OGP画像やSNSシェア用 | <NuxtImg>(<picture> はOGPクローラーに未対応の場合あり) |
| art direction(画面幅で異なる画像) | <NuxtPicture> + <source> のカスタム実装 |
主要プロパティの効果と設定方法
sizes ― レスポンシブ srcset の自動生成
sizes 属性は、ブレークポイントごとの表示幅を指定する最も重要なプロパティです。
<NuxtImg
src="/images/banner.jpg"
alt="バナー"
sizes="100vw sm:50vw md:33vw lg:400px"
/>
この指定により、各ブレークポイントに対応する幅の画像が srcset として生成されます。ブラウザは画面サイズとDevice Pixel Ratio(DPR)をもとに最適な画像を選択します。
densities ― Retina対応
densities 属性でDPR倍率を指定できます。デフォルト値は [1, 2] です。
<!-- 1xと2xの画像を生成 -->
<NuxtImg
src="/images/icon.png"
alt="アイコン"
width="64"
height="64"
densities="x1 x2"
/>
固定サイズのアイコンやアバターには densities を、フルードレイアウトの画像には sizes を使用するのが適切です。
quality ― 圧縮品質
0〜100の数値で画像品質を指定します。ファイルサイズと画質のトレードオフを意識した設定が重要です。
| 用途 | 推奨quality値 | 備考 |
|---|---|---|
| ヒーロー画像・メインビジュアル | 80〜90 | LCPに直結するため画質優先 |
| 商品画像・コンテンツ画像 | 70〜80 | バランス重視 |
| サムネイル・一覧画像 | 50〜70 | ファイルサイズ削減優先 |
| 背景・装飾画像 | 40〜60 | 視認品質を維持しつつ軽量化 |
preload と fetchpriority ― LCP画像の優先読み込み
ファーストビューに表示されるLCP(Largest Contentful Paint)画像には、preload 属性を付与します。
<NuxtImg
src="/images/hero.jpg"
alt="メインビジュアル"
sizes="100vw"
preload
/>
preload を指定すると、<head> 内に以下のようなタグが自動挿入されます。
<link rel="preload" as="image" href="/_ipx/w_1280/images/hero.jpg" imagesizes="100vw" imagesrcset="..." fetchpriority="high">
LCP画像には loading="lazy" を付けない のが鉄則です。preload 指定時は自動的に遅延読み込みが無効化されます。
loading ― 遅延読み込み
ファーストビュー外の画像には loading="lazy" を指定します。
<NuxtImg
src="/images/content.jpg"
alt="コンテンツ画像"
loading="lazy"
sizes="100vw md:80vw"
/>
loading 属性を省略した場合、ブラウザのデフォルト動作(eager)になります。ファーストビューのLCP画像以外は原則 lazy を指定してください。
placeholder ― 読み込み中の表示
画像の読み込み完了までプレースホルダーを表示できます。CLS(Cumulative Layout Shift)の防止にも寄与します。
<!-- 自動生成のぼかしプレースホルダー -->
<NuxtImg
src="/images/photo.jpg"
alt="写真"
placeholder
width="800"
height="600"
/>
<!-- サイズとぼかし量を指定 -->
<NuxtImg
src="/images/photo.jpg"
alt="写真"
:placeholder="[50, 25, 75, 5]"
width="800"
height="600"
/>
引数の順序は [幅, 高さ, 品質, ぼかし量] です。
画像プロバイダーの選び方
@nuxt/image は20以上のプロバイダーに対応しています。代表的なプロバイダーの特徴を比較します。
| プロバイダー | ホスティング | 料金目安 | WebP/AVIF | CDN | 適用場面 |
|---|---|---|---|---|---|
| IPX | セルフホスト | 無料(サーバーコスト) | 対応 | 自前で用意 | 小〜中規模サイト、SSR環境 |
| Cloudinary | クラウド | 無料枠あり(月25クレジット) | 対応 | 内蔵 | 画像加工が多いECサイト |
| imgix | クラウド | 月$5〜 | 対応 | 内蔵 | メディアサイト、高トラフィック |
| Vercel | Vercel専用 | Vercel料金に含む | 対応 | Vercel Edge | Vercelデプロイ時 |
| Netlify | Netlify専用 | Netlify料金に含む | WebPのみ | Netlify Edge | Netlifyデプロイ時 |
IPX(デフォルトプロバイダー)
IPXはNuxt Imageに組み込まれたセルフホスト型の画像処理エンジンで、内部的に Sharp(libvips)を使用しています。外部サービスへの依存がなく、サーバー上で画像のリサイズ・フォーマット変換・品質調整を行います。
// nuxt.config.ts - IPXの追加設定例
export default defineNuxtConfig({
image: {
ipx: {
modifiers: {
quality: 80,
format: 'webp',
}
}
}
})
Cloudinaryプロバイダーの設定
// nuxt.config.ts
export default defineNuxtConfig({
image: {
provider: 'cloudinary',
cloudinary: {
baseURL: 'https://res.cloudinary.com/your-cloud-name/image/upload'
}
}
})
<template>
<NuxtImg
provider="cloudinary"
src="/v1234567890/sample.jpg"
alt="Cloudinary画像"
width="600"
height="400"
/>
</template>
プロバイダーの混在利用
1つのプロジェクト内で複数のプロバイダーを使い分けることも可能です。
<template>
<!-- デフォルト(IPX)で処理 -->
<NuxtImg src="/images/local.jpg" alt="ローカル画像" />
<!-- Cloudinaryで処理 -->
<NuxtImg provider="cloudinary" src="/remote/photo.jpg" alt="外部画像" />
</template>
Core Web Vitalsを改善する実装テクニック
GoogleのCore Web Vitalsは検索順位に影響するランキングシグナルです。画像最適化はLCPとCLSの改善に直結します。
LCP(Largest Contentful Paint)の改善
LCPのスコアは「良好」が2.5秒以内、「要改善」が2.5〜4.0秒、「不良」が4.0秒超と定義されています(出典: web.dev)。
画像がLCP要素になるケースは非常に多く、改善には以下の戦略が有効です。
<!-- LCP画像のベストプラクティス -->
<template>
<NuxtImg
src="/images/hero.jpg"
alt="メインビジュアル"
width="1280"
height="720"
sizes="100vw lg:1280px"
quality="85"
format="webp"
preload
:densities="['x1', 'x2']"
/>
</template>
LCP改善のチェックリスト:
preload属性でプリロードを有効化するloading="lazy"を付けない(LCP画像を遅延させると逆効果)width/heightを明示してレイアウトシフトを防ぐsizesで適切な画像サイズを指定し、過大な画像の転送を回避するformat="webp"または<NuxtPicture>でファイルサイズを削減する
CLS(Cumulative Layout Shift)の防止
CLSは「良好」が0.1以下です(出典: web.dev)。画像読み込み時のレイアウトシフトを防ぐには、画像のアスペクト比を事前に確保する必要があります。
<!-- width/height でアスペクト比を確定 -->
<NuxtImg
src="/images/card.jpg"
alt="カード画像"
width="400"
height="300"
loading="lazy"
class="w-full h-auto"
/>
width と height を指定することで、ブラウザはCSSの aspect-ratio を自動計算し、画像読み込み前にスペースを確保します。CSSで width: 100%; height: auto; を併用するのが定番パターンです。
実装前後のスコア比較例
以下は、一般的なNuxtサイトで@nuxt/imageを導入した際の改善効果の目安です。
| 指標 | 導入前(目安) | 導入後(目安) | 改善率 |
|---|---|---|---|
| LCP | 4.0〜6.0秒 | 1.5〜2.5秒 | 40〜60% |
| CLS | 0.15〜0.30 | 0.01〜0.05 | 80〜90% |
| 画像転送量 | 3〜5MB | 0.8〜1.5MB | 60〜70% |
※ 値はサイト構成・画像枚数・サーバー環境により変動します。
レスポンシブ画像のパターン別実装
パターン1: フルブリード画像(画面幅いっぱい)
<NuxtImg
src="/images/wide-banner.jpg"
alt="全幅バナー"
sizes="100vw"
quality="80"
loading="lazy"
/>
パターン2: コンテナ幅に制限された画像
<NuxtImg
src="/images/article.jpg"
alt="記事画像"
sizes="100vw md:80vw lg:720px"
quality="75"
loading="lazy"
/>
パターン3: カード型レイアウト(グリッド)
<template>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div v-for="item in items" :key="item.id">
<NuxtImg
:src="item.image"
:alt="item.title"
width="400"
height="300"
sizes="100vw sm:50vw lg:33vw"
quality="70"
loading="lazy"
/>
</div>
</div>
</template>
パターン4: AVIF/WebP/JPEGの段階的フォールバック
<NuxtPicture
src="/images/photo.jpg"
alt="風景写真"
sizes="100vw md:80vw lg:960px"
format="avif,webp"
quality="80"
loading="lazy"
/>
<NuxtPicture> は format に指定した順序で <source> 要素を生成し、最後に元のフォーマット(JPEG等)をフォールバックとして配置します。
SSR・SSG・SPAモードごとの注意点
SSR(サーバーサイドレンダリング)
SSRモードではIPXがサーバー上でリクエストのたびに画像を処理します。初回リクエスト時に変換が行われ、以降はキャッシュから配信されます。
- IPXのサーバーサイド処理が利用可能
preloadタグが初期HTMLに含まれるため、LCPの改善効果が最大化される- サーバーのCPU・メモリリソースを消費する点に注意
SSG(静的サイト生成)
SSGモードではビルド時に画像が処理・生成されます。デフォルトプロバイダーは ipxStatic に切り替わります。
// nuxt.config.ts - SSG向け設定
export default defineNuxtConfig({
image: {
// SSG時は自動的にipxStaticが使用される
// staticFilenameでファイル命名規則を指定可能
staticFilename: '[publicPath]/images/[name]-[hash].[ext]',
}
})
- ビルド時に全画像バリアントが生成されるため、デプロイ後のサーバー負荷はゼロ
- 画像の追加・変更時は再ビルドが必要
- 生成される画像ファイル数が多い場合、ビルド時間が延びる
SPA(シングルページアプリケーション)
SPAモード(ssr: false)ではサーバーサイド処理が使えないため、制約があります。
- IPXのサーバー機能が利用不可
- Cloudinaryやimgixなどのクラウドプロバイダーの利用が推奨される
preloadタグは初期HTMLに含まれないため、LCPへの効果が限定的
外部ドメインの画像を最適化する
外部サイトの画像を @nuxt/image で処理するには、domains 設定でホワイトリスト登録が必要です。
// nuxt.config.ts
export default defineNuxtConfig({
image: {
domains: [
'images.unsplash.com',
'cdn.example.com',
],
}
})
<NuxtImg
src="https://images.unsplash.com/photo-xxxxx"
alt="Unsplash画像"
width="800"
height="600"
loading="lazy"
/>
IPXプロバイダー使用時は、リモートの画像がサーバー経由でフェッチ・変換されます。レイテンシを抑えるにはCDNの併用を検討してください。
presetsで画像設定を統一する
プロジェクト全体で画像設定を統一したい場合、presets が有用です。
// nuxt.config.ts
export default defineNuxtConfig({
image: {
presets: {
thumbnail: {
modifiers: {
width: 200,
height: 200,
fit: 'cover',
quality: 60,
format: 'webp',
}
},
hero: {
modifiers: {
width: 1280,
height: 720,
fit: 'cover',
quality: 85,
format: 'webp',
}
},
}
}
})
<template>
<!-- presetsを適用 -->
<NuxtImg preset="thumbnail" src="/images/avatar.jpg" alt="アバター" />
<NuxtImg preset="hero" src="/images/hero.jpg" alt="ヒーロー" />
</template>
preset を使うことで、コンポーネント側のコードを簡潔に保ちつつ、設定変更を nuxt.config.ts に集約できます。
よくあるトラブルと解決策
画像が表示されない
原因1: パスの指定ミス
<NuxtImg> の src は public/ ディレクトリからの絶対パスで指定します。assets/ ディレクトリの画像には対応していません。
<!-- NG: assets内の画像 -->
<NuxtImg src="~/assets/images/photo.jpg" />
<!-- OK: public内の画像 -->
<NuxtImg src="/images/photo.jpg" />
原因2: 外部ドメイン未登録
外部URLの画像を使う場合は domains への登録が必要です。
SPAモードでIPXが動作しない
ssr: false の環境ではIPXのサーバー処理が使えません。Cloudinaryやimgixなどのクラウドプロバイダーへ切り替えてください。
ビルド時に画像生成が遅い
SSGで大量の画像バリアントを生成する場合、ビルド時間が増大します。以下の対策が有効です。
screensのブレークポイント数を必要最小限に絞るdensitiesを[1, 2]に限定する([1, 1.5, 2, 3]のような過剰設定を避ける)- 画像枚数が多い場合はCloudinaryなどのクラウドプロバイダーで処理をオフロードする
placeholder が表示されない
placeholder 属性はIPXプロバイダーのSSR/SSGモードで動作します。SPAモードやクラウドプロバイダーでは使用できない場合があります。
まとめ
@nuxt/image は、<NuxtImg> と <NuxtPicture> の2つのコンポーネントで画像最適化の大部分を自動化するNuxt 3公式モジュールです。sizes によるレスポンシブ対応、preload と fetchpriority によるLCP改善、width / height 指定によるCLS防止など、Core Web Vitalsに直結する改善を少ないコード変更で実現できます。
IPXをはじめとする20以上のプロバイダーに対応しており、セルフホストからクラウドサービスまでプロジェクトの規模や要件に応じた選択が可能です。
公式ドキュメント: https://image.nuxt.com/
