PR

【効かない原因を完全解明】aspect-ratioの正体を暴く

HTML/CSSを学ぶ

みなさんこんにちは。

HTML/CSSにおいて、4:3や16:9など比率を維持した要素を作ることは長年の課題でした。かつてはpadding-topを使ってハック的に比率を維持する方法(記事の最後に軽く紹介します)が使われていましたが、少し前にaspect-ratioというまさに要素の縦横比を指定するためのプロパティが生まれました。

しかし、実はaspect-ratioを指定すれば絶対にその比率になる、というわけではないのです。皆さんも一度はaspect-ratioが効かなくて困った経験があるのではないでしょうか。

要素を思った通りのサイズにするためにも、aspect-ratioを改めて細かく理解していきましょう。かなり複雑なので、先に使い方を紹介した後になぜそうなるのかを詳しく解説していきます。

この記事を読めば、「aspect-ratioが効かない!」と悩むことはもうありません。

※かなり深く調べましたが、それでも間違っている可能性がありますのでご存じの方はご指摘ください。

使い方編(基本)

早速基本の使い方を見ていきましょう。

解説

よく使う指定方法は値による指定で、縦 / 横の順番に比率を書きます。加えて、

  • width, heightのどちらかが値で指定されている(px, %, vw, etc…)
  • もう片方はautoである

という条件を満たす必要があります。

.Sample {
  aspect-ratio: 16 / 9; /* 16:9の比率になる */
  width: 60%;
}

上記は通常の要素でしたが、imgタグやiframeのように後からコンテンツが読み込まれるようなタグ(置換要素と呼ばれます)の場合も同様です。

画像などの場合は以下のように明示的にheight: auto;を指定した方が良いです(詳しくは後述)。また、画像の元々の比率と違う場合は画像が歪まないようにobject-fitも併記しておきましょう。

<img
  width="1500"
  height="1125"
  src="任意の画像へのパス"
  decoding="async"
  alt=""
/>

※width, height属性をわざわざ書いている理由はこちら(https://itokoba.com/archives/7047)をご覧ください。値は元画像のサイズを指定しています。

.Image {
  aspect-ratio: 16 / 9;
  width: 60%; 
  height: auto;  
  object-fit: cover;
}

注意点:aspect-ratioが効かない場合

いくつかの理由により、aspect-ratioが効かない場合が存在します。個別に解説します。

CSS、もしくはタグのwidth, height属性によってサイズを決められた場合

width, heightがどちらも値で指定されているとaspect-ratioによる指定は無視されます。次の例をご覧ください。

.Sample {
  aspect-ratio: 16 / 9; /* widthとheightの両方が指定されているため、16:9の比率にならない */
  width: 60%;
  height: 30px;
}

上記コードの結果が下図です。明らかに16:9にはなっていません。

imgタグに属性を指定した場合も見てみましょう。

<img
  width="200"
  height="200"
  src="https://itokoba.com/asset-files/umi.webp"
  decoding="async"
  alt=""
/>
.Image {
  aspect-ratio: 16/9; 
  object-fit: cover;
}

この場合もimgタグに指定したwidth=”200″ と height=”200″ のサイズが優先されています。

このように、サイズが明らかに指定されている場合はaspect-ratioが効きません。

コンテンツによってサイズが決められた場合

CSSからではなく、画像や文章などのコンテンツによって要素のサイズが決定される場合があります。そういう時もaspect-ratioが効きません。

imgタグの場合、CSSのwidth, heightがどちらもautoかつタグのwidth, height属性の指定がないと画像の元々のサイズで表示されます。例として200×150の画像の場合を見てみましょう。

<img src="200x150の画像へのパス" alt="" />

この状態でaspect-ratioだけを指定しても残念ながらその比率にはなりません。元の画像のサイズのままになります。

また、テキストの場合も指定した比率をはみ出してしまう場合はそのサイズが優先されます。以下を見てください。

.Box {
  aspect-ratio: 16 / 9;
  width: 200px;
  background-color: skyblue;
}
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Animi, neque asperiores debitis itaque quisquam quae fuga omnis saepe voluptate laboriosam perspiciatis labore?

これも明らかに16:9ではなく縦長になっていますよね。このように、コンテンツによって決定されるサイズはaspect-ratioによる比率指定よりも優先されます。

概念編

基本的な使い方を見たところで、そもそもaspect-ratioが何をしているかを確認していきましょう。

aspect-ratioが決めるのは、推奨アスペクト比である

aspect-ratioは要素の縦横比を決めるプロパティと説明されがちですが厳密には「推奨アスペクト比」というものを決めるプロパティです。

.Sample {
  aspect-ratio: 16 / 9; /* これが推奨アスペクト比 */
}

推奨アスペクト比(英:preferred aspect ratio)はざっくり言うと、

「要素の縦横比が明示されていない、もしくは初期値に当たる縦横比がない場合に利用される縦横比」というものです。使い方編(基本)の注意点でも見たように、

  • すでに別のところで縦横の比率が明示されてしまっている
  • コンテンツのサイズが縦横比を決めている

場合にはこの推奨アスペクト比が利用されません。

繰り返しお伝えしているように、widthもしくはheightの片方のみがautoの場合に推奨アスペクト比が適用されます。

width: 60%; height: auto; の要素があったとします。

<div class="Box">テスト</div>
.Box {
  width: 60%;
  background-color: skyblue;
}

height: auto; なので要素の高さは中のコンテンツ分だけになります(下図)。

テスト

これにaspect-ratioによって推奨アスペクト比を追加すると指定した比率になります。

.Box {
  aspect-ratio: 16 / 9;
  width: 80%;
  background-color: skyblue;
}

こうすると要素は16:9の縦横比を持ちます(下図)。

テスト

imgタグでも同様です。

<img class="Image" width="1500" height="1125" src="任意の画像へのパス" />
.Image {
  aspect-ratio: 16 / 9;
  width: 60%; 
  height: auto;
  object-fit: cover;
}

imgタグの場合はheight: auto; を明示する理由ですが、タグにwidth, height属性がある場合それがデフォルトでCSSのプロパティの値としても使われているからです(下図)。

つまり上記の例で明示しなければwidth: 60%; height: 1125px; の要素になってしまいます。そうなるとwidth, heightがどちらも指定されていることになるのでaspect-ratioも効きません。

推奨アスペクト比が効かない理由と、早見表

改めて、aspect-ratioによる推奨アスペクト比が効かない場合をまとめると、

  • CSSや属性など、すでに別のところで縦横の比率が明示されている場合
  • コンテンツ(画像、文章など)によってサイズが決まる場合

です。とにかく他にアスペクト比が決まるような指定があればダメということです。逆にアスペクト比が自動計算される場合には推奨アスペクト比が効きます。

以下に具体的な要素とサイズ指定の種類の組み合わせを表にまとめました。

width: auto; height: auto;width, heightの片方のみauto;width, heightが両方とも値width, height属性が指定されている
通常の要素(divなど)効く(例外あり)効く(例外あり)効かない
置換要素(imgタグなど)効かない効く効かない効かない

この表はそれぞれ単体で指定した場合で考慮しています。

通常の要素の場合、width, heightの最低片方にautoが含まれていればアスペクト比は自動計算になります。よって推奨アスペクト比が適用されます(コンテンツの量がはみ出す場合を除く)。

画像の場合はwidth, heightが両方autoだと元の画像のサイズになってしまうため効きません。

ちなみにCSSのwidth, heightプロパティが最も優先度が高いため、width, height属性の指定がされていてもCSSでwidth, heightの片方のみauto; になるように指定していれば推奨アスペクト比が効きます。

使い方編(応用)〜なんとしても推奨アスペクト比を守らせる〜

さて、ここまでで基本的な使い方とaspect-ratioの仕組みについて解説してきました。次は応用的な使い方を見ていきます。

通常の要素の場合、コンテンツ量によって推奨アスペクト比をはみ出すと言いました。はみ出しているということは、overflowプロパティによって制御することができます。コンテンツによってはみ出している例を再掲します。

.Box {
  aspect-ratio: 16 / 9;
  width: 200px;
  background-color: skyblue;
}
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Animi, neque asperiores debitis itaque quisquam quae fuga omnis saepe voluptate laboriosam perspiciatis labore?

これにoverflow: auto; を追加します。

.Box {
  overflow: auto; /* 追加 */
  aspect-ratio: 16 / 9;
  width: 200px;
  background-color: skyblue;
}
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Animi, neque asperiores debitis itaque quisquam quae fuga omnis saepe voluptate laboriosam perspiciatis labore?

こうすることで要素の比率が維持され、コンテンツはスクロールが発生します。overflow: scroll; と明示してもいいですし、スクロールが必要なければoverflow: hidden; でも良いです。

こうすれば絶対に比率を維持させることができます。

aspect-ratioが効かなくて困った時のチェックリスト

  • スペルは間違っていませんか?(例:aspect-racio, apsect-ratio, etc)
  • 値を正しく設定していますか?スラッシュではなくコロンを使っていたりしませんか?
  • width, heightが両方とも値になっていませんか?画像の場合は両方autoもダメです。そうなっていませんか?

おまけ:padding-topでの比率維持

今となってはもう必要ありませんが、padding-topでの方法を軽く紹介します。

<div class="Box">
  <div class="Box__Inner">
    <div class="Box-Content">コンテンツ</div>
  </div>
</div>
.Box {
  width: 60%;
  background-color: skyblue;
}

.Box__Inner {
  position: relative;
  width: 100%;
  padding-top: 56.25%; /* これで16:9になる。4:3にしたいなら75%。 */
}

.Box-Content {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  padding: 20px;
}

これで比率が維持された要素が作れます。

コンテンツ

これはpadding-topを%で指定する際、「親要素のwidthに対する比率として計算される」という性質を利用したものです。要素自身のwidthではないことに注意してください。手順は以下の通り。

  1. 横幅を決定するための要素を用意する(.Box)
  2. 子要素を用意し、padding-topで%指定をする(.Box__Inner)
  3. さらに子要素を用意し、コンテンツを入れる(.Box-Content)。ただしpadding-topによって押し出されてしまうので、.Box__Innerにposition: relative; を、.Box-Contentにposition: absolute; を指定して戻す。

これで比率維持をしていました。

まとめ

というわけで、aspect-ratioについてでした。こうやって見ると結構効かない場面が多いですね。正直かなり複雑でまとめるのにも苦労しましたが参考になれば幸いです。

参考サイトは以下。MDNとW3CによるCSSの仕様書をかなり読み込みました。

https://developer.mozilla.org/ja/docs/Web/CSS/aspect-ratio

https://drafts.csswg.org/css-sizing-4/#aspect-ratio

https://drafts.csswg.org/css-display-4/#replaced-element

https://drafts.csswg.org/css-images-3/#natural-aspect-ratio

https://drafts.csswg.org/css-sizing-4/#preferred-aspect-ratio

コメント

タイトルとURLをコピーしました