👋

バナー画像の崩れを防ぐ!object-fit: containの活用術【Next.js対応】

に公開1

広告のバナー画像や外部サービスのロゴ画像を並べて表示したいとき、
元画像の縦横比がバラバラでレイアウトが崩れてしまう...という経験はありませんか?

例えば、

  • ある画像は横長、ある画像は正方形
  • それでも同じサイズの枠にぴったり収めたい
  • CSSだけでスマートに解決したい

今回は、そんな場面で役立つCSSプロパティ object-fit: contain; の使い方を、Next.js対応で解説します!

結論を一言で言うと、object-fit: contain;を使うことです。

object-fitとは?

mdnに記載がある通り、置換要素をコンテナーにどのように当てこむかを決定するものです。

※置換要素を簡単に説明すると、<img><video><iframe>のように、本質的にはHTMLの外で表現されている要素のことです。

object-fit: contain;は、アスペクト比を維持した上で拡大もしくは縮小するアプローチです。
高さもしくは幅の片方がぴったりと合うようになり、ぴったりと合わない方は余白になるイメージです。

各プロパティの違い

object-fit: contain;以外にもプロパティはあり、簡単に意味を説明すると以下のような表になります。

プロパティ 意味
contain アスペクト比を維持した上で拡大もしくは縮小する。
高さもしくは幅の片方が親要素にぴったりと合うようになり、ぴったりと合わない方は余白になる
cover アスペクト比を維持したまま拡大もしくは縮小する。
高さと幅の両方が親要素にぴったりと合うが、置換要素のサイズ調整はされず、一部が切り抜かれる感じになる
fill 親要素を埋め尽くすように無理に置換要素を引き延ばすイメージ
none デフォルト値。置換要素のサイズを特に調整せずに親要素の中に置いた感じになる
scale-down containもしくはnoneのうち、置換要素のサイズが小さい方が選ばれる。最初からcontainを指定する方が良い気がする、、、

Next.jsで使う方法(サンプルコード)

次のコードは、画像のサイズ比率が異なる複数の画像を、300×200の枠に収める例です。
それぞれの画像に object-fit を指定して、表示の違いを比較します。

Next.jsの<Image>コンポーネントでfillを使うと、画像は親要素いっぱいに広がる前提になります。
このとき、object-fitを組み合わせることでアスペクト比を維持しつつ、
表示崩れを防ぐことができます。

import styles from "./index.module.css";
import Image from "next/image";

export default function Page() {
  return (
    <>
      <h2>object-fitの実験</h2>

      <div className={styles.block}>
        <p className={styles.caption}>元画像サイズ: 1200×638</p>
        <div className={styles.imageContainer}>
          <Image
            src="https://cdn.hinatazaka46.com/images/14/dde/cee447de8a64f0fa1e5cf62941c0b.jpg"
            alt="日向坂46 全国ツアー2025SPECIAL SITE"
            fill
            className={styles.image}
          />
        </div>
      </div>

      <div className={styles.block}>
        <p className={styles.caption}>元画像サイズ: 640×640</p>
        <div className={styles.imageContainer}>
          <Image
            src="https://cdn.hinatazaka46.com/images/14/e18/3a5e52bf3213a3a9d6c894e2eb2dc.jpg"
            alt="日向坂46のロゴマーク"
            fill
            className={styles.image}
          />
        </div>
      </div>

      <div className={styles.block}>
        <p className={styles.caption}>元画像サイズ: 360×136</p>
        <div className={styles.imageContainer}>
          <Image
            src="https://cdn.hinatazaka46.com/images/14/58b/8bb49151fb491e7f7ef35203b6a3f-01.jpg"
            alt="ひなこい"
            fill
            className={styles.image}
          />
        </div>
      </div>
    </>
  );
}
.block {
  margin-bottom: 24px;
}

.caption {
  margin: 0 0 4px;
  font-size: 14px;
  color: #555;
}

.imageContainer {
  position: relative;
  width: 300px; /* 擬似的に要素の幅を設定 */
  height: 200px; /* 擬似的に要素の高さを設定*/
  border: 2px solid #ccc;
  background-color: #f9f9f9;
  overflow: hidden;
}

.image {
  object-fit: contain;
}

表示結果の比較

imageクラスに指定するobject-fitの値を変更すると、
表示のされ方が以下のように変わるのがわかります。

object-fit: contain;

アスペクト比を維持したまま高さもしくは幅の片方が親要素にぴったりと合うようになり、
ぴったりと合わない方は余白になる感じが伝わるかと思います。

object-fit: cover;

アスペクト比を維持するが、画像のサイズ調整が特にされずに親要素の幅や高さに合わせて切り抜かれる感じが伝わるかと思います。

object-fit: fill;

親要素を埋め尽くすように無理に画像を引き延ばすイメージが伝わるかと思います。

object-fit: none;

画像のサイズを特に調整せずに親要素の中に置いた感じになるのが伝わるかと思います。

object-fit: scale-down;

このケースでは、元画像が親要素より大きいため、scale-downcontainと同じ動作になります。

まとめ

  • バナー画像など、アスペクト比が異なる画像を均一に表示したいときは object-fit: contain; が便利
  • Next.jsの<Image>と組み合わせても、崩れずに表示できる
  • 表示方法は contain 以外にも複数あり、目的に応じて使い分けることが大切
  • 普通にはいる

特に広告バナーやロゴ一覧など、レイアウトの整合性が求められる場面で非常に役立つテクニックです!

Discussion

waddywaddy

確かめます

  • いいですね
  • そうなんですか?