🖼️

# Next.jsのImageが使いにくいという人へ

2022/03/19に公開

Next.jsのImageが使いにくいという人へ

2022/12/25:更新

暫定のシンプルな実装方法

いずれにせよheightは設定しないといけないことになります.これはCore Web VitalsのCLSを損ねるからでしょうね.

記事内にあるlayout='fill'はv13.0からはfillをtrueにすることで指定できます.この方法を取るしか無いでしょう.また記事内で扱わなかったaspect-ratioを使用することで,短く書くことも可能です.
また,objectFit='contain'も非推奨になったので,自分で追加すると良いでしょう.

以下例(TailwindCSSで失礼)

import type { FC } from 'react';

import NextImage from 'next/image';

export const Image: FC<Props> = () => {
  return (
    <div className="relative aspect-square">
      <NextImage
        className="object-contain"
        src={url}
        alt={alt || ''}
        fill
      />
    </div>
  );
};

今回の変更は一見何も使いやすくなってないかと思いますが,Core Web Vitals的には正しいと思います.
よくわからない人は,HTMLのimg要素にwitdhとheightが必須になったものくらいに思っておけばいいかと思います.ちょっとだるい感じですが,それだけすればいい感じにしてくれるのです.

参考
New
https://nextjs.org/docs/api-reference/next/image

Legacy
https://nextjs.org/docs/api-reference/next/legacy/image



Next.jsにはHTMLのimgタグよりNext.jsが用意したImage Componentを使用することが推奨されています.

Image Componentが何かわからない人は一度公式をご覧ください.

https://nextjs.org/docs/api-reference/next/image

私も詳しいことわからないのですが,Vercelなどの対応しているHostingサービスでデプロイするときにこのComponentを使っていると画像ファイルがいい感じになるようなので,できれば使っていきたいところです.

今回はそんなImage Componentが使いやすくなるための知識を浅く簡潔に記録しておきます.

この記事は2022/03/18頃に書かれたものであり,その後のアップデート次第で仕様が変わることもあるのでご注意ください.

ちなみに,結構前のアップデートでこのImage Componentは大分使いやすくなりました.私の最初のイメージはwidthとheightを指定しないと使えない使いづらいやつだったのですが,どうやら工夫すればそんなことしなくても良さそうです!

基本的な使い方

一般的にはHTMLのimgタグと同じようにsrcalt属性などを指定して使います.

import Image from 'next/image';

const MyComponent = () => {
  return (
    <div>
      {/* 通常のimgタグ */}
      <img src='/logo.png' alt='logo' />
      {/* Next.jsのImage Component */}
      <Image src='/logo.png' alt='logo' />
    </div>
  );
};

これだけ見ると簡単に思えるのですが,様々な条件が整っていないとNext.jsさんは劣化の如く怒り,実エラーのオンパレードになります.

ハマりやすい2つのポイント

srcのURLについて

まずはsrcの指定方法です.大きく2つあると思ってください.

publicフォルダから参照(型:string)

<Image src='/logo.png' layout='fill' alt='logo' />

いつもの書き方なのですが,publicフォルダ配下しか参照できないというのと,**layout属性をfillとしない場合にwidthとheightの指定を求められる**点だけ注意が必要です.

/hogehogeと書くことでpublic/hogehogeを表します.

そして,layout属性をfillとすると「え...」っとなります.(後で詳しく)

publicフォルダ以外からimportして参照(型:StaticImageData)

import Image from 'next/image';
import imageSrc from '../assets/logo.png'; // 相対パスや絶対パスは好みで

const MyComponent = () => {
  return (
    <div>
      <Image src={imageSrc} alt='logo' />
    </div>
  );
};

imageSrcという名前で画像ファイルを読み込み,Image Componentのsrcへ渡しています.

この場合,サイズは元の画像のサイズが表示されます.(調整方法は後で詳しく)

この方法では画像ファイルがどこにあろうが表示することができます.

スタイルの調整について

ここまでで画像を表示することができるものの思い通りにスタイル(CSSを当てる)ことができないという人のために自分がよく使っている簡単なテクニックを紹介します.

layout='fill'とする

<Image src={imageSrc} layout='fill' alt='logo' />

とすることで,目の前が画像に覆われることがあるでしょう.

これはposition: absolute;width: 100%;があたったようなものと思っていいでしょう.

なので,position: relative;を持つ親を探し続けてそこまで広がるわけです.

これを解決したい場合は

<div style={{ position: 'relative', width: '100px', height: '100px' }}>
  <Image src={imageSrc} layout='fill' alt='logo' />
</div>

のように親にwidthとheightが確保されている状態である必要があります.

またこれでは,画像のアスペクト比(画像の縦横比)を維持することが難しいため,objectFitを併用することをおすすめします.

例:

<div style={{ position: 'relative', width: '100px', height: '100px' }}>
  <Image src={imageSrc} layout='fill' objectFit='contain' alt='logo' />
</div>

objectFit='contain'とすれば,アスペクト比を保ったまま横いっぱいor縦いっぱいに広がり,余白が出るものの,画像全体が見えるようにしてくれます.

objectFit='cover'とすれば,アスペクト比を保ったまま横いっぱいor縦いっぱいに広がり,画像全体が見えなくてもいいので,余白がないようにしてくれます.

文章だと少し分かりづらいですが,これはCSS Propertyのobject-fitと同じ挙動です.

わからない人は,新しくなったMDNで確認してみるといいでしょう.

https://developer.mozilla.org/ja/docs/Web/CSS/object-fit

layout='responsive'とする

<Image src={imageSrc} layout='responsive' alt='logo' />

こちらはこのImage Componentの親のサイズに応じていい感じになってくれますので,比較的使いやすいです.

<div style={{ width: '100px' }}>
  <Image src={imageSrc} layout='responsive' alt='logo' />
</div>

とすれば,親の100pxに合わせて画像が横に広がり,高さはアスペクト比を保ったまま広がります.

画像にwidth: 100%;があたっている状態という感じですね.


というわけでケースバイケースではあるのですが,基本的で簡単なテクニックを紹介しました.

Discussion