👻

【学習アウトプット】padding-top: 100%;で画像をレスポンシブにアスペクト比を指定する

2024/03/08に公開2

はじめに

今回実現したいこと
カードレイアウトで画像サイズがバラバラの時でもカードのサイズを維持しつつ、
画像のアスペクト比を保って表示する。
下記画像のAfterのような状態です。

目指す状態(Afterの状態)

・Before

・After

実現方法

imgタグを囲む親クラスに対してpadding-top: 100%;
を指定すると、

親要素の幅に対して100%。つまりアスペクト比1:1で指定できる。
そして画像の配置は、親クラスの
"c-staff-card__img"
に対してposition: relative;を併用して指定し、
直下のimgタグに対して、

img {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 100%;
      height: 100%;
      object-fit: cover;
    }

を指定することによって、中央配置、カードの幅いっぱいに表示することができる。

完成コード

#HTML

<div class="c-staff-card">
  <div class="c-staff-card__img">
    <img
      src="./assets/img/c-staff-introduction-card__img.png"
      alt="歯科衛生士氏名"
    />
  </div>
  <div class="c-staff-card__namewrap">
    <p class="c-staff-card__job">歯科衛生士</p>
    <p class="c-staff-card__name">鈴木 太郎</p>
  </div>
  <dl class="c-staff-card__profile">
    <dt class="c-staff-card__profile-question">出身地</dt>
    <dd class="c-staff-card__profile-answer">北海道</dd>

    <dt class="c-staff-card__profile-question">趣味</dt>
    <dd class="c-staff-card__profile-answer">スキー、料理</dd>

    <dt class="c-staff-card__profile-question">好きな食べ物</dt>
    <dd class="c-staff-card__profile-answer">お寿司、うなぎ</dd>
  </dl>
</div>

#Scss

.c-staff-card {
  max-width: 335px;
  @include global.mq(lg) {
    max-width: 280px;
  }
  &__img {
    position: relative;
    width: 100%;
    border-radius: 20px;
    overflow: hidden;
    padding-top: 100%; //このおかげで画像サイズ1:1を保てる!

    @include global.mq(lg) {
      max-width: 280px;
    }

    img {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      border-radius: 20px;
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
  }
}

なぜこの方法でアスペクト比を維持できるのか

この方法は、padding-top、もしくはpadding-bottmをパーセンテージで指定することによってアスペクト比を保持する。というCSSの計算上の特性を使用したもので、
親要素の幅に基づいて高さを相対的に定義することで機能する。

【応用】この方法でアスペクト比16:9にしてみる

今回の場合は画像サイズは1:1で指定したかったので100%だが、
応用として、もし画像サイズをよくある16:9で指定する場合は、このpadding-topのパーセンテージの値をカードの横幅に基づいて指定することでアスペクト比を維持することができるはず。

今回はmax-width: 280px;で指定したいので、
16:9だと画像サイズは280px * 157.5pxになってればOK

変更点

.c-staff-card {
  max-width: 335px;
  @include global.mq(lg) {
    max-width: 280px;
  }
  &__img {
    position: relative;
    width: 100%;
    border-radius: 20px;
    overflow: hidden;
        padding-top: 56.25%; //アスペクト比9:16

    @include global.mq(lg) {
      max-width: 280px;
    }

    img {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      border-radius: 20px;
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
  }
}

できた。

まとめ

この方法ならどんなバラバラの画像サイズのものでもサイズを揃えつつ、画像のアスペクト比を保つことができるのでどんな案件でも応用できるし、WordPressとかでどんどん画像が後から追加されるようなものに対しても強そう。何よりシンプルなので破綻も起きない。

今までpaddingの値はpx,rem,emでしか指定してなかったから%で指定する方法は大きな学びでした。

Discussion

rithmetyrithmety

懐かしい
昔はこういう書き方してましたね

数年前くらいから aspect-ratio が使えるようになって使わなりましたが…

tomy_devtomy_dev

公式ドキュメントを見ながらaspect-ratio使って試してみたら実際にできました!古い書き方だったんですね、とても勉強になります。ありがとうございます!