概要
next/imageは画像を自動で最適化してくれる便利なコンポーネントです。
使用には基本的にサイズ(width, height)を事前に指定する必要がありますが、APIから画像を受け取って表示する場合など、事前にサイズを指定したくないケースがあると思います。
この記事では、そのような場合でもnext/imageを使って画像を表示する方法をご紹介します。
環境としては、Next 12.1.2 を使用します。
Next.js 13以上を使用する場合は、こちらの記事をご覧ください。
実装方法
最終的なコードはこちらになります。
// JS
<div className={styles.imageContainer}>
<Image
className={styles.image}
src={path}
layout="fill"
objectFit="contain"
/>
</div>
// CSS
.imageContainer {
>span { // ⭐️ Next12未満では span -> div に変更する必要があります。詳細は後ほど説明します。
position: unset !important;
}
.image {
position: relative !important;
width: 100% !important;
height: unset !important;
}
}
順を追って見ていきます。
layout="fill"を指定する
next/imageは必ずwidth + height
またはlayout="fill"
を指定する必要があります。
本記事では、サイズ指定しないのでlayout="fill"
を指定します。
どちらも指定しなかった場合は、下記のエラーが表示されます。
Error: Image with src "xxx" must use "width" and "height" properties or "layout='fill'" property.
next/imageのスタイルを上書きする
next/imageで生成される要素は、「<img>」+「<img>をラップする要素」となっています。
「<img>をラップする要素」は、Nextのバージョンで違いがあります。
- Next 12未満:<div>タグでラップされる
- Next 12以降:<span>タグでラップされる
実際に生成される要素はこちらです。
// <Image src={path} layout="fill" objectFit="contain" />
// こちらを指定した際に生成される要素
<span
style="
box-sizing:border-box;
display:block;
overflow:hidden;
width:initial;
height:initial;
background:none;
opacity:1;
border:0;
margin:0;
padding:0;
position:absolute;
top:0;
left:0;
bottom:0;
right:0
"
>
<img
style="
position:absolute;
top:0;
left:0;
bottom:0;
right:0;
box-sizing:border-box;
padding:0;
border:none;
margin:auto;
display:block;
width:0;
height:0;
min-width:100%;
max-width:100%;
min-height:100%;
max-height:100%;
object-fit:contain
"
...
/>
</span>
<span>
<img>
にposition:absolute;
が設定されているので、そのままのスタイルだと画像が表示されません。そのため、表示されるようにスタイルを上書きしていきます。
1. <span>のスタイルを上書きする
.imageContainer {
>span { // ⭐️ Next12未満では span -> div に変更する必要があります。
position: unset !important;
}
<span>
にスタイルを当てるためには、next/imageをdivなどでラップする必要があります。
これはnext/imageにクラス名を指定すると<img>
にクラス名が付与されてしまい、<span>
に直接スタイルを当てるすべがないためです。
ラップした要素から<span>
に対して、position:absolute;
をposition: unset !important;
で上書きします。
2. <img>のスタイルを上書きする
.image {
position: relative !important;
width: 100% !important;
height: unset !important;
}
次に、<img>
のスタイルを上書きします。
こちらは以下の3点を上書きします。
position:absolute;
→position: relative !important;
width: 0;
→width: 100% !important;
height: 0;
→height: unset !important;
これでアスペクト比を保ちつつ画像を表示させることができます。