Next.jsでの画像最適化を実装した手順と効果
最近、自分のポートフォリオサイトをNext.jsで書き換える作業を進めています。デザインを重視するあまり、画像ファイルが重くなりがちで、ページの表示速度が気になっていました。そこで、Next.jsが標準で備えている画像最適化機能を取り入れ、Core Web Vitalsの改善を目指しました。FukuokaからTokyoへ移って以来、アプリの動作確認もスマートフォン中心に行うことが増えたため、モバイル環境での体感を最優先にしたいと考えたのがきっかけです。
今回の記事では、next/imageコンポーネントを使った具体的な設定手順と、実際に測定したパフォーマンスの変化をまとめます。同じような課題を抱えている方の参考になれば嬉しいです。
画像の課題と改善の方針
サイトを監査したところ、ヒーロー画像とサムネイルの一覧がLighthouseのLCP指標を大きく押し上げていました。特に、トップページに掲載している制作事例のスクリーンショットは、元データがRetina想定で書き出されていたため、平均的なファイルサイズが500KBを超えていたのです。
そのまま放置すると、訪問者は表示を待つ間に離脱しやすくなります。デザインの質は保ちつつ、転送量を抑える手段を検討した結果、Next.jsの画像最適化パイプラインに白羽の矢が立ちました。これまでのPalnartPOCの構築事例でも、画像の扱いが課題になっていたため、同じ手法を整理し直す良い機会になりました。
next/imageの基本と特徴
next/imageコンポーネントは、画像の遅延読み込み、リサイズ、现代的なフォーマットへの変換を自動的に行ってくれます。srcsetやsizes属性を細かく書かなくても、デバイスピクセル比に応じた適切なサイズを返してくれるのが大きな魅力です。
さらに、sharpライブラリを内部的に利用しているため、ビルド時にWebPやAVIFへの変換が用意されています。レイアウトシフトを防ぐためのwidthとheightの指定も、コンポーネント側の仕組みで吸収されるため、CSSを細かく調整する必要がありません。
導入準備とライブラリ選定
Next.js 13以降のApp Routerを採用しているため、画像設定はnext.config.jsにまとめる方針にしました。まずは出力ディレクトリをpublic配下に統一し、remotePatternsを使用して外部CDNを参照する画像のドメインも許可しておきます。
また、プレースホルダー機能を使うためにimport blur-up effectを採用しました。低画質のBase64を事前に生成しておき、本画像を読み込むまでの間を滑らかに埋めてくれます。セットアップ段階でつまづきやすいのは、既存のimgタグとの置き換え漏れです。grepで一気に置換し、type属性の指定を見直しました。
実装の流れとコード例
実際のコンポーネントは、以下のように整理しました。alt属性は装飾用の画像なら空に、意味を持つ画像なら具体的な説明文を入れるようにルール化しています。
import Image from 'next/image'
import heroDesktop from '@/public/images/hero-desktop.jpg'
export function Hero() {
return (
<Image
src={heroDesktop}
alt="制作事例の表紙ビジュアル"
placeholder="blur"
priority
sizes="(max-width: 768px) 100vw, 50vw"
quality={80}
/>
)
}
priorityはLCP対象のヒーローにだけ付けています。カード一覧など画面下に配置する画像は、自動的に遅延読み込みされる設定に任せました。さらに、ページ遷移時には専用のLoadingコンポーネントを用意し、体感速度を底上げしています。
Lighthouseスコアと実測値の改善
最適化を適用する前のスコアは、モバイルでLCPが4.2秒、CLSが0.18でした。差し替え後はLCPが2.1秒、CLSが0.04まで改善し、パフォーマンススコアは64から92に跳ね上がりました。
この結果は、GraphQLで取得している制作事例の一覧にも反映しています。以前は同じデータ量でもレンダリング完了まで時間がかかっていましたが、画像周りのブロッキングが解消されたことで、体感がかなり軽くなりました。定量的な数値を公開することで、自分の設計判断の振り返りにも役立っています。
つまずきポイントと学び
実装を進めてみると、SVGをそのままnext/imageに流しても期待した最適化がかからないことが分かりました。SVGは内部で自動変換の対象外となるため、別途インライン化する方針に切り替える必要があります。
加えて、CMSから取得した画像はドメインが動的に変わることがあり、remotePatternsの許可リストに追従しなければなりません。運用フェーズを見据えて、画像URLの整形ロジックを一箇所に集約しました。発表資料を過去に公開したスライドの中でも、画像の扱いはよく議題に上がります。今回の知見は次の勉強会でも共有する予定です。
画像最適化は一度入れれば終わりではなく、コンテンツ運用と両輪で改善していくテーマです。Next.jsのバージョンアップに合わせて設定も見直していくつもりです。
あなたのプロジェクトでも、もし画像の重さがボトルネックになっているなら、next/image導入の一歩目を試してみてください。LCPの改善はユーザーの満足度に直結する効果が得られます。実装で分からないことがあれば、コメント欄やSNSで相談してもらえれば、私の分かる範囲でお答えします。同じような課題に取り組んでいる方のデベロッパーズミートアップのレポートにも、画像最適化の話題がよく登場するので、合わせて読んでみるとモチベーションが上がるかもしれません。