LoginSignup
21
10

More than 1 year has passed since last update.

Next.jsのImageが覚えられないよ〜

Last updated at Posted at 2022-12-13

はじめまして、株式会社エイチームウェルネスの@ayanerv_2045です。

名前に「2045」が入っているのは、エンジニアリングの勉強を始めた当時毎日退屈していて、はやくシンギュラリティが来てほしかったからです。

普段はデザイナーとして主にグラフィックの制作をしていますが、たまに簡単なフロントエンドの業務も担当するので、今回アドベントカレンダーに参加させていただきました。
実は初めてのQiita執筆です。お手柔らかにお願いします:writing_hand:

はじめに

この記事では、Next.jsでのフロント開発で登場するImageコンポーネントの便利な使い方について説明します。

  • たまにしかフロントを触らないせいで永遠にImageの使い方が覚えられない
  • 見よう見まねでImageを使ってみるが、エラー祭りで気が滅入ってしまう
  • 画像サイズのレスポンシブな調整をjsにやってもらいたい
  • HTMLは書けるけど、HTMLと違うNext.js特有のあれこれにつまずきがち

という私のような方におすすめです。

この記事を読んでImageコンポーネントの使い方を覚えると、このように高さも幅もいい感じに可変する、綺麗なレスポンシブデザインが実現できます!

ezgif-3-133abf2a4f.gif

Next.jsのImageって?

Next.jsでは画像を表示するとき、HTMLのimgタグよりもNext.jsが用意したImageコンポーネントを使用することが推奨されています。

そもそもImageコンポーネントとは、Next.jsのビルトインコンポーネント(簡単な記述で最初から使えるようにNext.jsさんが用意してくれているもの)です。

▼より詳しい説明はこちらで(日本語翻訳版です)

 
次のコードのように、Imageを使いたいtsxファイルの先頭でimportしておけば、ページ内のどこでも<img>タグの代わりにImageを使えるようになります。

pages.tsx
import Image from 'next/image';

{/* 中略 */}

<Image
  src='/santa.jpg'
  alt='クリスマスの写真'
  width={400}
  height={400}
/>

altやwidth・heightを持たせるところはHTMLと同じです。

srcは、publicフォルダ配下を参照しますので、画像は基本的にpublicに置きましょう。public配下にフォルダを作って細かく画像を管理することも可能です。
上のコードでは、

pages.tsx
src='/santa.jpg'

と書くことで、public/santa.jpgを参照しています。

ワンポイントアドバイス
Imageコンポーネントは、ほとんどの場合でwidth・heightの指定を要求してきます(エラー吐きます)。
widthとheightの数値は、表示したい画像の画面上での大きさ、あるいはその画像の元の大きさを記述しておいてください。

width・heightの指定がいらないパターンは後ほど説明します。

layoutを設定して、画像をレスポンシブ対応しよう

ここからが本題です。

Next.jsのImageコンポーネントは、「いい感じに画像のサイズを調整してくれる」ように作られています。
例えば、画像を囲むDOM要素の幅が小さくなるにつれて、比率を保ちながら画像の幅もそれに合わせて調整してくれたり。

しかし、画像が思い通りにサイズ調整されるようなスタイリングをするには、いくつかのプロパティの使い方を覚えて、正しく使う必要があります。
layoutobjectFitobjectPositionです。

layoutから順に説明します。

layout

ビューポート(画像を表示する範囲)のサイズが変わった時、画像がどのような挙動をするかを設定するプロパティです。
正しく記述すれば、このような挙動が実現できます。
(記事冒頭でお見せしたものと同じです)

ezgif-3-133abf2a4f.gif

上手く使えば綺麗なレスポンシブデザインを実装できそうだなぁというのが伝わるでしょうか?
ビューポート(画像を表示する範囲)のサイズが小さくなっても、アスペクト比を崩すことなく画像の表示範囲が可変し、しかも右側のテキストの高さと揃っています。
CSSで書くと地味にややこしいこういった挙動が、プロパティの使い方さえ覚えれば2,3行で書けます。

では、layoutプロパティにはどのような値があるのか紹介していきます。

intrinsic

デフォルトの値です。layoutプロパティを何も記述しないとintrinsicになります。
元の画像サイズの横幅を上限に、アスペクト比を保って拡大縮小します。
シンプルに画像を表示するだけならこれでも良いのですが、下のGIFのようにテキストなど他の要素と並ぶとガタガタしますね。

ezgif-3-ba5b885f11.gif

fixed

読んで字のごとく、widthとheightが固定になります。

ezgif-3-38f801b44e.gif

responsive

出ました、responsiveです。
筆者は最初Imageを使った時この辺りから「覚えられないよ〜」となっていました。

responsiveにすると、表示範囲の横幅に合わせて拡大縮小します。

ezgif-3-3b71ae5d0c.gif

これだけみると別に普通に拡大縮小しているだけなのですが、次に出てくるfillや、fillとペアで登場するプロパティのobjectFitを使った挙動と混同していたのです…。

私のように混乱しないためには、「responsiveは横幅可変」と覚えると良いです。
PC〜タブレット〜SPへと画面幅が変わっても、滑らかに要素のサイズが変わって崩れないデザインのことを「レスポンシブデザイン」って言いますよね。
よく考えるとあれは画面の高さではなく幅に応じて変化するものなので、「レスポンシブということは横幅可変か〜」と思うと覚えやすいかもしれません。

ちなみに私は「レスポンシブ=なんかいい感じに空気読んで可変してくれるもの」と勘違いしていて、「あれっ高さは親要素に合わせてくれないの?」と混乱してました。

なお、responsiveは親要素がdisplay: blockでないと上手く動きませんので気をつけてください。

fill

高さと幅の両方を親要素いっぱいにして、画像の表示範囲を埋めます。
CSSのbackground-size: coverみたいな挙動です。

fillにすると、画像が画面いっぱいに広がってしまうことがあります。
その場合は、親要素をposition: relative;とし、widthとheightを持たせるようにしてください。

 
先程のlayout={"responsive"}の場合、横幅は可変しても高さは隣のテキストと揃わずガタガタしていました。
しかしfillは高さと幅両方に合わせて広がるので、隣のテキストとも高さが揃い、綺麗なレスポンシブデザインを実現できます。

ezgif-3-9da563d3b3.gif

…と思いきや、fillはこれだけではアスペクト比を無視してしまい、上のようになります。
ここで登場するのが、layoutに続くもう一つのプロパティ、objectFitです。

objectFit

objectFitは、CSSにおけるobject-fitと使い方も挙動も同じです。

例えば、objectFit={"cover"}というようにImageコンポーネントに記述します。
この時、Imageコンポーネントがクライアント側でimgタグに変換されたものに当たっているスタイルを見ると、object-fit: coverが当たっているのが分かります。

スクリーンショット 2022-12-13 12.14.36.png

▼CSSにおけるobject-fitについてはこちら

 
先ほどlayout={"fill"}と記述したときにアスペクト比を無視して拡大縮小していたのは、このobjectFitを記述することで解決できます。

  • fill
  • cover
  • contain

のいずれかを指定して、fillの挙動を決められます。

cover

ezgif-3-ceb6a85705.gif

coverの場合は、画像の表示範囲全体を覆うように画像が拡大縮小します。
CSSのbackground-size: coverみたいな挙動です。
表示範囲全体を覆う代わりに、画像の一部が見えなくなってしまうため、画像が切れると困る場合は、

  • 被写体を写真の中央に配置して、切れないようにする
  • objectPositionプロパティをImageコンポーネントに渡して、親要素内にどう配置されるかを定義しておく

のどちらかで対処しましょう。
objectPositionプロパティの記述はCSSと同じですので、今回は割愛させていただきます。

contain

ezgif-3-bd3e7e9089.gif

containの場合は、画像全体が表示範囲に入るように調整されます。
CSSのbackground-size: containみたいな挙動です。
coverと違って画像が切れることはありませんが、画像の表示範囲に余白ができることがあります。
(ちょっと上のGIFだとわかりにくいですね…すいません)

これらのプロパティを組み合わせると

冒頭でご紹介した、「ビューポート(画像を表示する範囲)のサイズが小さくなっても、アスペクト比を崩すことなく画像の表示範囲が可変し、しかも右側のテキストの高さと揃う」デザインを実装できます。

layout={"fill"}で「画像を高さ・幅に合わせて拡大縮小」よう設定しつつ、objectFit={"cover"}で「アスペクト比を保って表示範囲いっぱいに画像を広げる」ように指定しています。

ezgif-3-133abf2a4f.gif

pages.tsx
<div className={styles.santa_wrap}>
  <p>▼これを目指します</p>
  <div className={styles.santa_flex}>
    <div className={styles.santa_image}>
      <Image
        src='/santa.jpg'
        alt='クリスマスの写真'
        layout={"fill"}
        objectFit={"cover"}
      />
    </div>
    <p className={styles.santa_text}>
      メリークリスマス!今年もアドベントカレンダーの季節がやってきたね!<br />
      メリークリスティアーノロナウド!今年もアド弁当カレンダーの季節がやってきたね!<br />
      メリークリス松村!!今年もアドベントカレーの季節がやってきたね!<br />
      メリークリスマス!今年もアドベンチャー滝沢カレンの季節がやってきたね!<br /><br />
      クリスマスとは、イエス・キリストの降誕祭です。クリスマスとは、イエス・キリストの降誕祭です。クリスマスとは、イエス・キリストの降誕祭です。<br/>
      すごいですね。
    </p>
  </div>
</div>
santa.css
.santa_wrap {
  max-width: 70%;
}
.santa_flex {
  display: flex;
  justify-content: space-between;
}
.santa_image {
  flex-basis: 48%;
  position: relative;
  margin-right: 20px;
  display: block;
}
.santa_text {
  flex-basis: 48%;
  margin: 0;
}

最後に

ここまで、Next.jsのImageコンポーネントについて説明しました。
Imageコンポーネントは、よくよく考えるとCSSと同じような部分が多く、混乱することもないかもしれないのですが、今までHTMLをメインに書いていたデザイナーや初見の人はプロパティの書き方がわからず身構えると思います。
そういった方向けにImageコンポーネントのプロパティについて動画付きで説明している記事はあまり見かけないので、お役に立てれば嬉しいです。

21
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
10