Next.js には画像を表示する 2 つの方法があります:next/image の <Image> コンポーネントと、プレーンな HTML の <img> タグです。間違った選択をすると、パフォーマンスか柔軟性のどちらかを 失います。それぞれをいつ使うべきかを解説します。
next/image が行うこと
<Image> コンポーネントは、次を追加する <img> のラッパーです:
- 自動 WebP/AVIF 変換:ブラウザのサポートに基づいて JPEG と PNG を WebP または AVIF に変換します。
- 自動 srcset 生成:
deviceSizesとimageSizesの設定を使用して複数のサイズバリアントを作成します。 - 遅延読み込み:フォールド以下の画像はビューポートに入ったときのみ 読み込まれます(ネイティブの
loading="lazy"を使用)。 - レイアウトシフト防止:
widthとheightプロップでスペースを確保し、CLS を防ぎます。 - ブラープレースホルダー:完全な画像が読み込まれる間、低品質の プレースホルダーを表示します。
- 優先読み込み:
priorityプロップが LCP 画像に<link rel='preload'>を追加します。
next/image のトレードオフ
自動化には制約が伴います:
- サーバーサイド処理:画像はリクエスト時(または最初のリクエスト後に キャッシュ)にサーバーで変換されます。これはコールドスタートの遅延とサーバー CPU コストを追加します。
- 必須の寸法:
widthとheightプロップを 指定するか、fillモードを使用する必要があります。サイズが不明な ユーザーアップロードコンテンツでは扱いにくい場合があります。 - リモートドメインのホワイトリスト:外部画像ドメインは
next.config.jsでの設定が必要です。 - 静的画像のオーバーヘッド:事前変換済みの WebP 画像も、必要のない 最適化パイプラインを通ります。
next/image を使うべき場合
- CMS またはデータベースからの動的画像(不明な寸法、様々な形式)
- 事前処理できないユーザーアップロード画像
- 手動でファイルを生成せずに自動 srcset が必要な場合
- 最小限のコードでブラープレースホルダーや優先読み込みが必要な場合
プレーンな img タグを使うべき場合
- 事前最適化済み画像:ビルド時にすでに WebP または AVIF に変換された 画像は next/image 処理のメリットがありません。
- 既知の固定寸法:ソースを管理していてすでに正しくサイズ調整した 静的アセット。
- サーバーサイドコストの回避:変換のオーバーヘッドが重要で代わりに 画像を事前処理できる高トラフィックページ。
- 完全な HTML 制御:複数のソース、アートディレクション、またはカスタム 読み込み動作を持つ複雑な
<picture>要素。
パフォーマンス比較
| シナリオ | next/image | img タグ |
|---|---|---|
| 最初のリクエスト(コールド) | 遅い(サーバー変換) | 速い(事前変換) |
| 以降のリクエスト | 速い(エッジキャッシュ) | 速い(CDN/ブラウザキャッシュ) |
| ビルド時間 | 速い | 遅い(事前変換の場合) |
| サーバー CPU | 使用あり | 使用なし |
| srcset | 自動 | 手動 |
ハイブリッドアプローチ
多くの本番 Next.js アプリは両方を使用します。動的コンテンツ(ブログ記事の画像、CMS の 商品写真)には <Image> を、事前最適化した静的アセット(ヒーロー画像、 アイコン、イラスト)にはプレーンな <img> を使います。
静的画像を WebP に事前変換するには Picovert のコンバーターを使用するか、Sharp を ビルドパイプラインに組み込んでください。完全な比較は next/image vs 事前変換の記事を 参照してください。
よくある間違い
- sizes プロップの欠落:
sizesなしでは Next.js が100vwをデフォルトにし、デスクトップで不必要に大きな画像を読み込みます。 実際のレンダリングサイズに合わせて常にsizesを設定してください。 - LCP 画像に priority を設定しない:フォールド上のヒーロー画像は ページで最も重要な画像を遅延読み込みしないよう
priorityを設定すべきです。 - 位置指定された親なしで fill モードを使用:
fillは 親がposition: relativeと明示的な寸法を持つ必要があります。