各ブラウザ対応!アスペクト比を保ったまま要素を幅可変に対応させる方法

レスポンシブ対応、もっと言えば各ブラウザ・ブラウザ幅でも表示崩れを起こさないのが常識とされるようになったコーディング作業。
各要素も当然アスペクト比を保って縦横比を崩さず表示させたい!
うろ覚えのまま毎回調べてるから、記事としてアウトプットすることでちゃんと理解しようと思います。

2020.06.05. Bootstrapでの場合も追記しました。

2020.12.01. Google MAPをアスペクト比を保って配置する場合も追記しました。

1: imgタグで画像ベタ貼り編

これは簡単というかそのままなんですけど、基本 is 大事。

img {
  width: 100%;
  height: auto;
}

2: iframeで動画を埋め込む編

iframeはwidthやheightにautoを指定することができないので、1: imgタグで画像ベタ貼り編のやり方はできません。
そこで、iframe自体でアスペクト比を保った高さを指定するのではなく、iframeを包む親要素を作成し、さらのその擬似要素padding-topでアスペクト比から割り出した%を指定することによって高さを設定します。

参考:そもそもpadding-topの%って何? どこ基準?

下記サイトの記事できれいにまとめられているので参照なさってください。


padding、そしてmarginもパーセント指定した場合は、親要素の幅を基準にするんですね。
そのため、親要素にpaddog-topで高さ指定するのではなく、擬似要素の方にpaddog-topを%指定して、横幅の比率を保った高さにします。

padding-topのアスペクト比指定ですが、%ではなくcalc()でも指定できます。
むしろそっちの方がスマートなのですが、IE11で例えばwidth: calc(100% / 3);などの場合に表示崩れが起きてしまいます。ハックを使うか、%指定で表記を統一するか、チームのやり方にしたがいましょう。

Youtube動画を配置

例として友達が歌を担当しているYoutube動画を配置してみます。
埋め込みたい動画の共有から埋め込むで埋め込みコードを取得します。
iframeタグ内にwidthとheightの指定が入っていますが、そのままでも削除しちゃってもOKです。ここではシンプルなコードにしたいので削除しました。

<div class="iframe_wrapper">
  <iframe src="https://www.youtube.com/embed/Un05KNjlUaQ" frameborder="0" allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>

Youtube動画のアスペクト比は16:9なので、高さは横幅の56.25%となります。この56.25%を親要素の擬似要素にpadding-topで指定します。

埋め込むiframeの幅、高さはどちらも100%を指定します。
position: absolute; width: 100%; height: 100%; top: 0; left: 0;なので、親要素のサイズぴったりになります。

div.iframe_wrapper {
  position: relative;
  width: 100%; /* ここは適時編集してください(px指定してmin-widthと組み合わせるなり) */
}
div.iframe_wrapper::before {
  content:'';
  display: block;
  padding-top: 56.25%; /* 高さ÷横幅×100 */
}
div.iframe_wrapper iframe {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}

埋め込み結果: 埋め込みコードそのまま編

iframeの高さが固定のためブラウザ幅が小さくなった場合、はみ出してしまいます。

埋め込み結果: 埋め込みコードのwidthを100%に、heightをautoにしてみた編

幅は100%になったのですが、高さ指定がおかしくなってしまいました。
(ちなみに、heightも100%にしてみた場合、chromeではautoの場合と変化ありませんでした)

埋め込み結果: 親要素で囲んでアスペクト比固定した編

親要素div.iframe_wrapperで囲みます。
ブラウザ幅を狭めてみてください。横幅に合わせて高さも比率が崩れることなく可変してくれます。

Google MAP埋め込み

前述の「埋め込み結果: 親要素で囲んでアスペクト比固定した編」のifameタグ部分をGoogle MAPの埋め込みコードに変更してみます。
埋め込みコード内のwidthheightのサイズ指定は消しています。

こちらも親要素div.iframe_wrapperの擬似要素で設定した高さ比率をキープして配置されました。

3: ブロックレベル要素編

使用頻度が高いのはこのパターンだと思います。
2: iframeで動画を埋め込む編の応用になりますが、こちらはアスペクト比を設定したい要素にheight: 100%;を指定して親要素のサイズに合わせるのではなく、 position: absolute; top: 0; left: 0; bottom: 0; right: 0;を指定して親要素のサイズの位置に引き伸ばす設定をします(ニュアンス分かりますでしょうか……)。

<div class="testBlock_wrapper">
 <div class="testBlock">幅の50%の高さです。</div>
</div>
div.testBlock_wrapper {
  position: relative;
  width: 100%; /* ここは適時編集してください(px指定してmin-widthと組み合わせるなり) */
}
div.testBlock_wrapper:before {
  content:'';
  display: block;
  padding-top: 50%; /* 高さ÷横幅×100 */
}
div.testBlock_wrapper div.testBlock {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background: #b9b2a2; /* 表示確認用 */
}

配置結果

ここでは幅:高さ=2:1→padding-top:50%;で指定しました。ブラウザ幅を狭めてみてください。

幅の50%の高さです。

padding-topとパーセンテージ指定については、前述2: iframeで動画を埋め込む編内の「参考:そもそもpadding-topの%って何? どこ基準?」で触れています。

アレンジ:画像を背景画像として配置

先ほどのブロック要素をアレンジして画像を配置してみます。
こないだ買ったジャンプコミックスの写真です(ロボコはいいぞ)。ご覧のとおり正方形ですね。
ジャンプコミックス

子要素のdiv.testBlockに、ここでは簡単に作業するためインラインでbackground-image:url(画像の位置); background-size:cover; background-position:center center;を指定しています。

ブログの一覧ページでサムネイル画像のサイズを合わせたり、下層ページでh1タイトル周りの画像埋め込みにいいかな?

Bootstrap4.0での場合

メインどころのアスペクト比に限られますが、Bootstrapでは要素にclassを指定することで反映されます。
親要素にembed-responsiveとアスペクト比を指定するclassを付加し、子要素のiframeにembed-responsive-itemを付加します。

アスペクト比 class
21:9 embed-responsive-21by9
16:9 embed-responsive-16by9
4:3 embed-responsive-4by3
1:1 embed-responsive-1by1

Bootstrap、便利ですね〜〜〜。

Youtube動画を埋め込んでみる

Youtube動画は16:9なので、親要素にembed-responsiveembed-responsive-16by9を付加します。

<div class="embed-responsive embed-responsive-16by9">
  <iframe class="embed-responsive-item" src="https://www.youtube.com/embed/Un05KNjlUaQ" allowfullscreen=""></iframe>
</div>

Google MAPを埋め込んでみる

前述のYoutube動画埋め込みのコードのiframeの部分をGoogle MAPのものに差し替えています。
Google MAPは埋め込みコードを取得する際にサイズを選択できますが、ここではそのwidthheightの部分を消しています。

<div class="embed-responsive embed-responsive-16by9">
  <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d112591.4596485567!2d129.19515896491515!3d28.13177753690181!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x351e2ea1947fe195%3A0xb33ae5569eea19bf!2z5Yqg6KiI5ZGC6bq75bO2!5e0!3m2!1sja!2sjp!4v1606801602168!5m2!1sja!2sjp" frameborder="0" style="border:0;" allowfullscreen="" aria-hidden="false" tabindex="0"></iframe>
</div>

親要素いっぱいになってアスペクト比を保たれていますね。
楽ですが、比率のバリエーションがあまり無いのがネックかも。

Bootstrap5ではclass名が変更になりratio ratio-16x9のようにシンプル化しています。詳しくは下記サイトをご参照ください。