Loading [MathJax]/extensions/tex2jax.js

2025/02/26

テクノロジー

Next.jsの画像最適化の落とし穴

この記事の目次

マイナビジョブサーチ WebチームのK.Kです。
今回は、Next.jsの画像最適化のお話をしたいと思います。

先日インフラ担当の方からこんな指摘をされました。
「Acceptヘッダーを転送していないから、画像の最適化が活かされていない。」
最初よくわからなくて「?」となったので、これをきっかけにNext.jsの画像最適化について調べてみました。

Next.jsの画像最適化とは?

Next.jsではimgタグ、または、next/imageのImageコンポーネントを使用して画像を描画します。

この内、next/imageを使用すると、画像の最適化を行うことができます。
「リサイズ」「フォーマット変換」などを行うことで、ページ読み込み速度が向上するなどといった恩恵が得られます。

リサイズ

リサイズの機能では、表示するディスプレイの大きさに合わせて、画像のサイズを最適化してくれます。

例えばジョブサーチ上のこの画像、以下のように記載されています。

srcset属性に複数のURLが並んでいることがわかります。
これらが、画面サイズごとの画像のパスを示しています。

PC
https://jobsearch.mynavi.jp/_next/image?url=%2Fapi%2FserveImage%3Furl%3Dhttps%253A%252F%252Fmynavi-agent.jp%252Fjobsearch%252Fimg%252Fjobimg%252Fjob1_01%252F02.webp&w=3840&q=75

SP(よりさらに少し狭めた場合)
https://jobsearch.mynavi.jp/_next/image?url=%2Fapi%2FserveImage%3Furl%3Dhttps%253A%252F%252Fmynavi-agent.jp%252Fjobsearch%252Fimg%252Fjobimg%252Fjob1_01%252F02.webp&w=640&q=75

PC だと「690 × 398」SPだと「640 × 369」の画像が表示に使用されます。
容量を比べると23KB vs 18KBと、SPの方が小さくなっています。
特にSPは通信環境によってページ表示が遅くなりがちなので、容量が小さくなるのは嬉しいですね!
元画像がもっと大きい場合は、より大きな差になるかと思います。

画面サイズごとの画像のパスは、next/imageを使用すると、自動で生成されます。
これらの中から最適な画像をブラウザ上に表示してくれます。

フォーマット変換

フォーマット変換では、ブラウザが対応している画像フォーマットに合わせて、画像フォーマットを最適化してくれます。

どういったフォーマットに変換するかは設定で変更することができ、デフォルトではWebPに変換される設定になっています。

module.exports = {
  images: {
    formats: ['image/webp'],
  },
}

WebPは、JPEGやPNGより圧縮率の高いフォーマットです。
他にAVIFも指定できますが、こちらはより圧縮率が高い代わりに、エンコードに時間がかかるようです。

さて、ジョブサーチのこちらの画像を取り上げます。

この画像、元はJPEGとして保存されています。
これをジョブサーチ上で開くと、JPEGで表示されます。
WebPじゃないの?
Chromeの最新版だから対応しているはずだけど?

そう、これが冒頭で書いた、今回指摘された内容です。

「ブラウザが対応している画像フォーマットに合わせて」画像フォーマットを最適化
ブラウザが対応している画像フォーマット、これは何で判断しているのでしょうか?
それが、Acceptヘッダーなんです。

↓ Acceptヘッダーとは?

HTTP の Accept リクエストヘッダーは、クライアントが理解できるコンテンツタイプを MIME タイプで伝えます。

実際にChromeでリクエストヘッダーのAcceptを見ると「image/webp」の記載があります。
Next.jsではこの値を見て、WebPで返すかどうかを判断しているわけですね。

公式ドキュメントにも以下の記載がありました。

Good to know:
~ 省略 ~
If you self-host with a Proxy/CDN in front of Next.js, you must configure the Proxy to forward the Accept header.

参照元:https://nextjs.org/docs/app/api-reference/components/image#formats

ジョブサーチでは、Next.jsの動作環境にAcceptヘッダーを転送していなかったため、WebPのブラウザがフォーマットに対応しているか判定できず、そのままのJPEGフォーマットで返していたようです。

それでは、実際にAcceptヘッダーを転送して、フォーマットの変換をするとどうなるのか、検証環境で動作させてみました。
すると、

  • 元画像(JPEG, 2000×1333):120KB
  • Acceptヘッダーなし(JPEG, 916×611):41KB
  • Acceptヘッダーあり(WebP, 916×611):20KB

ということで、画像の容量が半分になりました!(圧縮されすぎでは?)
見た目上は変化がわからないのに、これはすごいですね!

最後に

next/imageで画像の最適化をすることで、ページの読み込みが早くなったり、他にも視覚的な安定性が得られたりといったメリットがあります。
SEOにおいてもメリットがあるので、せっかくNext.jsを使用しているなら、動作しているのかちゃんと確認しないとなと思いました。

参考

https://nextjs.org/docs/app/building-your-application/optimizing/images
https://nextjs.org/docs/app/api-reference/components/image#formats
https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Accept

※本記事は2025年02月時点の情報です。

著者:マイナビエンジニアブログ編集部