Closed2
next/imageで縦横比が不明の画像を扱う
next/imageのImage
コンポーネントでは原則width
とheight
の指定が必須。縦横比があらかじめ分かっている場合はこれでOK。
とはいえ縦横比が事前に分からない画像を扱う必要もあり、そういう場合にwidht
とheight
を決めてしまうと本来と異なる縦横比で表示されてしまう。一つの解決策は、
-
layout='fill'
とobjectFit='contain'
オプションを指定してwidth
とheight
は決めない。 - コンポーネントを
div
で囲んでこのdiv
にposition: relative
とwidth
(またはheight
)のスタイルを適用。
というもの。
気になるのは、
-
width
とheight
を指定した場合と比較したパフォーマンス面での差異 -
Image
がうまく回避しているというCLS(Cumulative Layout Shift)対策はどうなっているか
放置してしまった。この間にNext.js 11がリリースされ、ローカルに保持している画像の width
と height
の自動検出機能が追加された。
さて、しばらく先述の方法を使ってみたところ、特にパフォーマンス面での問題の原因になるということはなかった。スタイル上の指示に過ぎないので当然ともいえる? 「width
とheight
の指定を構造的に強制する」というnext/imageの設計は優秀で、画像が原因のCLSはこの方法でも完全に排除されていた。
実践的には毎回書くのは億劫なのでもっぱらコンポーネント化したものを使うことになる。ついでに何らかの理由で画像が読み込めないとき alt
のテキストを出すよりは NoImage 的なデフォルト画像を表示したいので、onError
で state を切り替えることにして、だいたいこんなふうなコンポーネントを定義する:
import { useState } from "react";
import Image from "next/image";
const ImageWithUnknownDimensions = (props: {
src: string;
alt: string;
className: string;
}) => {
const [state, setState] = useState<{ src: string }>({ src: props.src });
return (
<div className={props.className}>
<Image
src={state.src}
alt={props.alt}
layout="fill"
objectFit="contain"
onError={() => setState({ src: "/noimage.png" })}
/>
</div>
);
};
export default ImageWithUnknownDimensions;
注意として、state を使っている都合かページングしている場合に遷移で中身が切り替わらないことがあるので、その場合は key
を付与するなりなんなりして更新を強制する。
比率の問題はこれでほぼ対処できたので、このスクラップはclose。
このスクラップは2021/08/03にクローズされました