アスペクト比の理解と設定

ページにレンダリングされるすべての要素は、高さと幅を持ち、したがって、幅と高さの比であるアスペクト比を持ちます。メディアオブジェクトの自然な寸法は、サイズ指定、拡大縮小、ズーム、境界を適用しないサイズであり、自然なサイズまたは内在サイズと呼ばれています。要素の内在サイズは、ボックスサイズ指定のような整形ルールを適用したり、境界線、マージン、パディングの幅を設定したりするのではなく、要素自体によって決定されます。

サイトを開発するとき、要素の幅をビューポートまたは親コンテナーのサイズに対するパーセント値に設定し、それに比例して高さを変更することで、ビューポートのサイズに応じて特定のアスペクト比を維持できるようにしたいと思うことがよくあります。画像や動画のような置換要素の場合、特定のアスペクト比を維持することはレスポンシブウェブデザインを作成するために必要なだけでなく、良いユーザー体験を提供するための重要な要素でもあります。資産のアスペクト比を設定することで、読み込み時のジャンク、すなわちページが描画された後にメディアが読み込まれたときに発生するレイアウトのずれであり、資産用の空間がが確保されていないため、再フローが発生することを防ぐことができます。

CSS を使用すると、置換された要素と置換されていない要素のサイズを縦横比に基づいて調整することができます。このガイドでは、aspect-ratio プロパティについて学び、置換された要素と置換されていない要素のアスペクト比について説明します。

aspect-ratio プロパティの動作

CSS の aspect-ratio プロパティの値は、要素のボックスの好ましい幅と高さの比率を定義します。値は <ratio>、キーワード auto、または空白で区切られた両方の組み合わせのいずれかです。

<ratio> は幅と高さの比率です。これは 2 つの正の数値 (<number>) をスラッシュ (/) で区切るか、1 つの <number> で表します。単一の数値を使用する場合、比率を <number> / 1 と書くのと同じで、これも幅を高さで割った値になります。

以下の値はすべて等価です。

css
aspect-ratio: 3 / 6;
aspect-ratio: 1 / 2;
aspect-ratio: 0.5 / 1;
aspect-ratio: 0.5;

以下の値もすべて等価です。

css
aspect-ratio: 9/6;
aspect-ratio: 3/2;
aspect-ratio: 1.5;

auto キーワードの効果は、このキーワードが適用された要素が置換された要素であるかどうかに依存します。アスペクト比を持つ置換された要素の場合、auto はアスペクト比を使用することを意味します。それ以外のすべての場合、auto 値はボックスに優先する縦横比がないことを意味します。どちらの場合も、これは aspect-ratio プロパティが適用されていない場合の既定の動作です。

auto キーワードと <ratio> 値の両方を含む場合、例えば aspect-ratio: auto 2 / 3;aspect-ratio: 0.75 auto; などは、auto 値は自然なアスペクト比で置換された要素に適用され、width / height または <number> の指定された比率が優先アスペクト比として使用されます。

上記の定義に「優先」という単語があることにお気づきでしょう。aspect-ratio の値が設定されても、常に適用されるわけではありません。aspect-ratio プロパティは「優先」アスペクト比を設定するため、ボックスのサイズの少なくとも 1 つが自動の場合にのみ効果を発揮します。

高さと幅、またはインラインサイズとブロックサイズの両方が明示的に設定されている場合、aspect-ratio プロパティの値は無視されます。この場合、どの寸法も自動的にサイズ設定されることは許されません。優先サイズは明示的に設定されますので、aspect-ratio プロパティは何の効果もありません。インラインサイズとブロックサイズの両方を宣言した場合は、そちらが優先されます。

置換要素では、どちらかの寸法に(auto 以外の)値を明示的に設定しない場合、どちらも既定で内在するサイズになります(aspect-ratio の値は適用されません)。aspect-ratio は、明示的に寸法が設定されていない非置換要素に適用されます。非置換要素は内在的または外在的のどちらかのサイズになり、コンテンツ、コンテナー、ボックスモデルのプロパティなどからサイズを取得します。

要素がページにレンダリングされるとき、CSS が適用されず、HTML のサイズ属性も含まれていなければ、ユーザーエージェントはオブジェクトを自然なサイズでレンダリングします。

置換要素のアスペクト比を調整する

<img><video> などの置換要素は、設定された寸法を持ち、したがって固有のアスペクト比を持つメディアに置き換えられます。JPEG、PNG、GIF のようなラスター画像を考えてみましょう。画像をページ上に配置し、<img> 属性か CSS で高さや幅を設定しない場合、その画像は固有のサイズで表示されます。

これは CSS が適用されていない 220px の正方形の画像で、内在サイズまたは既定のサイズで表示されます。

置換コンテンツが auto でサイズ指定されている場合、または width に値を設定するなどして 1 つの寸法だけにサイズを指定した場合、ブラウザーはメディアの元の縦横比を維持したまま、もう 1 つの寸法(この場合は高さ)のサイズを自動的に変更します。

この例では、width だけが画像に設定されているので、ユーザーエージェントはその縦横比を保持します。55px110px、そして width: auto 値による自然なサイズである 220px で表示されます。

両方の次元でサイズを指定した場合のみ、置換要素が歪む危険性があります。例えば、画像に width: 100vw;height: 100vh; を設定すると、アスペクト比が可変になります。ビューポートのアスペクト比が画像の自然なアスペクト比と異なる場合、画像は引き伸ばされたり、つぶされたりして表示されます。

この例では、同じ画像が 3 回繰り返され、height の値は同じ (110px) ですが、width の値は異なるサイズ (55px110px220px) に明示されています。

heightwidth の両方を設定することで、画像を意図的に歪ませています。最初の画像はつぶれ、3 番目の画像は引き伸ばされています。

CSS の aspect-ratio プロパティを使用して、1 つの寸法を設定し(両方でもどちらでもない)、1 (または 1 / 1)以外の値を指定することで、これと同じ歪んだ効果を作成することができました。おそらくこのようなことはしたくないでしょうが、可能であることを知っておくのは良いことです。

css
img {
  height: 100vh;
  aspect-ratio: 3;
}

ここでは 1 つの次元のみを宣言しています。100vh は例の <iframe> ビューポートの全高です。aspect-ratio が置換された要素に適用されるためには、1 つの次元のみを設定する必要があります。両方を設定しても、どちらも設定しても動作しません。

置換要素をコンテナーに収める

本来の縦横比を維持したまま、置換要素をコンテナーの寸法に合わせるには、object-fit プロパティの値を cover または contain に設定します。これにより、置換要素はリサイズされ、コンテナーを「覆う」ようにクリップされるか、コンテナー内に完全に「収まる」ように小さなサイズで表示されます。

この例では、正方形の画像は 3 つのアイテムのグリッドに配置され、それぞれのアスペクト比は 5 / 2 である。

まず始めに、3 つのアイテムを持つコンテナーを作成し、それぞれに画像を 1 つずつ入れます。

html
<div class="grid">
  <div>
    <img
      src="https://mdn.github.io/shared-assets/images/examples/progress-pride-flag.jpg"
      alt="Pride flag" />
  </div>
  <div>
    <img
      class="cover"
      src="https://mdn.github.io/shared-assets/images/examples/progress-pride-flag.jpg"
      alt="Pride flag" />
  </div>
  <div>
    <img
      class="contain"
      src="https://mdn.github.io/shared-assets/images/examples/progress-pride-flag.jpg"
      alt="Pride flag" />
  </div>
</div>

次に、コンテナーをグリッドに設定し、各アイテムの縦横比を 2.5 (5/2) とし、最小幅を 150px とします。したがって、最小の高さは 60px となります。しかし、最終的な幅と高さは、例の iframe の幅、つまりビューポートのサイズに基づいて決定されます。

css
.grid {
  display: grid;
  gap: 20px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  font-size: 0; /* ホワイトスペースを最小化するため */
}

div div {
  aspect-ratio: 5 / 2;
  background-color: #ccc;
}

次に画像のサイズを決め、最後の 2 つの画像に object-fit プロパティを設定します。

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

.cover {
  object-fit: cover;
}

.contain {
  object-fit: contain;
}

最初の画像だけが歪んで(引き伸ばされて)います。object-fitfill 値を使っても同じ効果が得られます。cover 画像はコンテナーの幅いっぱいに広がり、垂直方向にセンタリングされ、コンテナーに収まるように切り取られます。contain 値は、画像をコンテナー内に確実に収め、水平方向の中央に配置し、収まるように縮小します。

非置換要素のアスペクト比の定義

置換要素のアスペクト比は既定で維持されますが、非置換要素の内在サイズを変更すると、通常はそのアスペクト比が変わります。例えば、同じ内容がワイド画面やワイドな親コンテナーでは 3 行で表示され、狭い画面やコンテナーでは 8 行で表示されることがあります。

この例では、同じ引用文が 200px600px の幅のコンテナーに表示され、200px の幅と同じ高さの正方形が設定されています。

それぞれの方向のサイズによって非置換要素の縦横比を設定する問題を強調するために、overflow プロパティを autovisible の間で切り替えてみましょう。

css
blockquote {
  width: 200px;
}

blockquote:nth-of-type(2) {
  width: 600px;
}

blockquote:nth-of-type(3) {
  height: 200px;
}

寸法を設定して、はみ出したコンテンツを非表示にすることで、非置換要素に縦横比を定義することは可能ですが、CSS aspect-ratio プロパティによって、明示的な縦横比を指定できます。これは、コンテンツや画面サイズがわからない場合でも、特定のアスペクト比を設定できることを意味します。

次の例では、非置換要素である aspect ratio: 1<blockquote> に設定することで、テキストの幅に関係なく正方形のボックスを表示します。

css
blockquote {
  inline-size: max-content;
  aspect-ratio: 1;
}

それぞれのボックスには寸法が一方だけ定義されています。inline-size は、横書き言語での幅を表し、max-content に設定されます。2 番目の寸法、この場合は block-size または height は、1 番目の寸法と同じ長さに設定されます。これは aspect-ratio プロパティで実現されます。要素のボックスの幅と高さの比率を 1 、つまり正方形の 1 / 1 と定義しました。これにより、heightblock-size プロパティを使用せずに、ブロックの方向が要素の幅と一致するように設定されます。

これらの例では、要素自体にサイズが明示的に設定されています。非置換要素で作業する場合、サイズ寸法が明示的に設定されていないと、アスペクト比が問題になります。

コンテナーのサイズに応じた円の作成

非置換ブロックレベル要素の inline-size は、そのコンテナーのコンテンツボックスのサイズです。これらは既定でサイズを持っているので、aspect-ratio プロパティが動作するために明示的にサイズを設定する必要はありません。

この例では、コンテナーの <div> の幅が 200px で、各辺に 5px のパディングが含まれています。したがって、コンテンツボックスのインラインサイズは 190px となります。ネストされた <p> 要素に高さや幅を設定しなくても、その行内サイズは 190px であることがわかります。aspect-ratio: 1 を設定すると、段落の高さは 190px になります。目に見えるコンテンツがはみ出すと高さが大きくなるはずです(ここではそうなりません)。

<div> 要素の高さは明示的に設定されていませんが、高さ 190px の段落、5px の上下のパディング、<p> の既定の上下のマージンを合わせた高さを含んでいます。その結果、幅よりも高さが大きくなっています。どちらの要素も border-radius の値が 50% であるため、コンテナーは楕円となります。子要素は aspect-ratio1 であるが、インラインまたはブロック方向の大きさが明示的に定義されていないため、円になります。

html
<div><p>Hello world</p></div>
css
div,
p {
  border-radius: 50%;
}

div {
  width: 200px;
  padding: 5px;
  background-color: #66ccff;
}

p {
  aspect-ratio: 1;
  text-align: center;
  border: 10px solid #ffffff;
  background-color: #f4aab9;
}

<div> を円にするには、heightwidth を同じ値に設定するか、aspect-ratio: 1 を設定し、overflowauto または hidden に設定します。また、margin-block: 0 を使って段落のマージンを削除することもできます。これらのオプションを以下に示します。

html
<section>
  <div><p>Hello world</p></div>
  <div><p>Hello world</p></div>
  <section></section>
</section>
css
div,
p {
  aspect-ratio: 1;
  border-radius: 50%;
}

div:first-of-type {
  overflow: hidden;
}

div:last-of-type p {
  margin-block: 0;
}

主な aspect-ratio の用途

ここでは、レスポンシブデザインを作成する際に、aspect-ratio を使用して一般的な課題に対処できる状況をいくつか見てみましょう。

外部資産をレスポンシブにする

TikTok、YouTube、Instagram の動画など、サードパーティが埋め込んだコンテンツであっても、すべてのコンテンツはレスポンシブであるべきです。これらの外部動画を埋め込むために含めるコードスニペットは、一般的に <iframe> を作成します。

<video> 要素は通常メディアファイルのアスペクト比を採用しますが、iframe 要素にはこの機能がありません。このため、<iframe> 要素が含まれる動画のアスペクト比を常に維持しながら、レスポンシブであることを保証するという課題が生じます。使用できるテクニックの 1 つは、iframe の幅をそのコンテナーの 100% または 100vw に設定し、ビューポートのサイズに関係なくビューポートの幅に一致させることです。しかし、高さを固定にすると、動画が引き伸ばされたり、つぶされたりする可能性があります。代わりに、動画のコンテナーに aspect-ratio を設定し、動画と同じアスペクト比になるように配置します。問題は解決しました!

ちなみに、デスクトップパソコンやノートパソコンで見る場合、YouTube 動画の標準的なアスペクト比は 16:9 だが、TikTok や Instagram の動画のアスペクト比は 9:16 である。

css
.youtube {
  aspect-ratio: 16/9;
}

.instagram,
.tiktok {
  aspect-ratio: 9/16;
}

aspect-ratio プロパティと一緒に @media クエリー内の aspect-ratio 機能を使用することで、iframe とそれが含む動画の両方のサイズを調整することができます。これにより、特定のアスペクト比を維持しながら、ビューポートのサイズに関係なく、動画コンテンツが常に可能な限り大きく(ビューポートの幅または高さいっぱいに)表示されるようになります。

横向きの YouTube 動画はビューポートと同じ幅に設定し、縦向きの TitTok と Instagram の動画 iframe はビューポートと同じ高さに設定します。ビューポートのアスペクト比が 16:9 より広い場合は、YouTube 動画をビューポートの高さに設定します。ビューポートが 9:16 より狭い場合は、Instagram と TikTok の動画をビューポートの幅に設定します。

css
iframe.youtube {
  aspect-ratio: 16/9;
  width: 100vw;
  height: auto;
}

iframe.instagram,
iframe.tiktok {
  aspect-ratio: 9/16;
  height: 100vh;
  width: auto;
}

/* ビューポートがとても広く、高さがあまりない場合 */
@media (aspect-ratio > 16 / 9) {
  iframe.youtube {
    width: auto;
    height: 100vh;
  }
}

/* ビューポートの縦幅がとても大きく、横幅があまり大きくない場合 */
@media (aspect-ratio < 9 / 16) {
  iframe.instagram,
  iframe.tiktok {
    height: auto;
    width: 100vw;
  }
}

正方形のグリッドセルを作成

正方形のセルのグリッドは、列トラックサイズを固定で定義し、各行が列トラックのサイズと確実に一致するようにすることで作成することができます。しかし、コンテナー内に可能な限り多くの列トラックを収めるために auto-fill を使用してレスポンシブグリッドを作成する場合、各項目の幅が不確かになります。そのため、正方形のアイテムを作成するための適切な高さを決定することが難しくなります。

アイテムにアスペクト比を設定することで、グリッドアイテムがレイアウトされたときに、各グリッドアイテムが幅と同じ高さになるように保証し、コンテナーの寸法に関係なく正方形のグリッドアイテムを作成します。

正方形のグリッドアイテムのこの例では、グリッドのトラックは自動サイズになり、アイテムのサイズを取ります。各アイテムの幅は少なくとも 95px ですが、もっと広くすることもできます。幅に関係なく、各アイテムは正方形になり、高さは幅と一致するように aspect-ratio によって決定されます。

css
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(95px, 1fr));
}

.item {
  aspect-ratio: 1;
}

グリッドアイテムのコンテンツが aspect-ratio で設定した推奨する高さを超えて大きくならないようにするには、min-height0 に、overflowvisible 以外の値に設定します。これは内在サイズのコンテンツに対して動作します。これは内在的に利用できる空間よりも大きなコンテンツを持つ場合、max-height(コンテンツによっては max-width)を 100% に設定することで、そのコンテンツがグリッドアイテムよりも大きくならないように設定します。

css
.item {
  min-height: 0;
  overflow: auto;
}

.item > * {
  max-height: 100%;
}

関連情報