📷

【Next.js v13】Imageコンポーネントを使ってレスポンシブ対応する

2022/12/28に公開2

こんにちは、フロントエンドエンジニアのShumpei(@seventhseven)です。

個人サイトで使っているNext.jsのバージョンをうっかり13に上げてしまいました。
それによってnext/imageも仕様が変わり、その結果モバイル表示時のレイアウトが崩れてしまいました。

今回はnext/image画像のレスポンシブ対応を修正した話になります。

バージョン

  • Next.js: 13.1.1
  • React.js: 18.2.0

結論:Imageコンポーネントのラッパーを作った

ページのある部分で使っているImageコンポーネントが対象だったため、
汎用的なCSSを付与した薄いラッパーを用意し、それを使用する方式を取りました。

import Image from "next/image";

export default function MyImageWrapper({ src, alt }) {
  return (
    <div className="relative">
      <div className="imageContainer">
        <Image src={src} alt={alt} fill responsive className="imageItem" />
      </div>
    </div>
  );
}

Imageコンポーネントにはfillresponsive属性を追加しました。
fill属性がついているため、Imageコンポーネント自身にはwidthとheightを付与しなくてもエラーになりません。
(responsive属性も同時につけるのは正しいのか要確認)

CSSはそれぞれのDOMにつけています。

  • 一番外側のdiv ... relativeクラス
  • 真ん中のdiv ... imageContainerクラス
  • Imageコンポーネント ... imageItemクラス
.relative {
  position: relative;
}

.imageContainer {
  height: 100%;
}

.imageItem {
  object-fit: contain;
  position: relative !important;
}

Imageコンポーネントは描画時に自動的にposition: absoluteがつけられるため、
position: relative !importantで打ち消します。
打ち消さないと画像分の高さが確保できません。
importantをつけるのはなかなか憚られますが。。。

また、使う時はさらに外側に横幅を指定したDOMを用意します。
この横幅分だけ画像が表示されます。

まとめ

まだまだ自分はnext/imageの理解が浅く、このような形を取りました。
個人サイトなので、色々と試している途中です。
レスポンシブは必須な要素なので、よりよい方法を探っていきたいと思います。

Discussion

MonMon

16:9の画像限定となりますが、親要素に「aspect-video」を指定した上で子要素(Image)に「object-cover」とfillをつけるとシンプルに収まるので多用しています。