aspect-ratio

Avatar of Geoff Graham
Geoff Graham on

Grow sales with Customer Journey Smarts Mailchimp tracking pixel

The CSS property aspect-ratio lets you create boxes that maintain proportional dimensions where the height and width of a box are calculated automatically as a ratio. It’s a little math-y, but the idea is that you can divide one value by another on this property and the calculated value ensures a box stays in that proportion.

.element {
  aspect-ratio: 2 / 1; /* ↔️ is double the ↕️ */
}

.element {
  aspect-ratio: 1 / 1; /* ⏹ a perfect square */
}

aspect-ratio is defined in the CSS Box Sizing Module Level 4 specification, which is currently in Working Draft. That means it’s still in progress and has a chance of changing. But with Chrome and Firefox supporting it behind an experimental flag, and Safari Technology Preview adding support for it in early 2021, there are strong signals that aspect-ratio is gaining a lot of momentum.

Syntax

aspect-ratio: auto || <ratio>;

In plain English: aspect-ratio is either assumed to be auto by default, or accepts a <ratio> as a value where <width / height>.

  • Initial value: auto
  • Applies to: all elements except inline boxes and internal ruby or table boxes
  • Inherited: no
  • Percentages: n/a
  • Computed value: specified keyword or a pair of numbers
  • Animation type: discrete

Values

/* Keyword values */
aspect-ratio: auto; /* default */

/* Ratio values */
aspect-ratio: 1 / 1; /* width and height are equal proportion */
aspect-ratio: 2 / 1; /* width is twice the height*/
aspect-ratio: 1 / 2; /* width is half the height */
aspect-ratio: 16 / 9  /* typical video aspect ratio */

/* Global values */
aspect-ratio: inherit;
aspect-ratio: initial;
aspect-ratio: unset;

It works on replaced and non-replaced content

If you’re thinking, “Uhm, yeah, doesn’t the browser already do this for us on images?” the answer is: absolutely. Browsers do some fancy aspect ratio calculations on replaced content like images. So, if an image has, say, a width of 500px, the browser flexes its CSS layout algorithms to maintain the image’s intrinsic or “natural” dimensions. The aspect-ratio property can be used to effectively override those natural dimensions.

But non-replaced content does not have a natural proportion. That’s most of the stuff we work with, like divs. Rather than try to maintain the element’s natural proportions, aspect-ratio sets a “preferred” sizing.

Now, the spec currently notes that older CSS specifications, notably CSS 2.1, does not contain a clear distinction between replaced and non-replaced content. That means we could see some additional special cases added to the spec to help clarify them. For the time being, we’re seeing browsers rolling out support for setting preferred aspect ratios on replaced and non-replaced separately, where some of the browsers with early support behind an experimental flag might only support aspect-ratio for non-replaced content. Definitely worth keeping an eye on the browser support as it evolves.

It works on its own without specifying a width or height

So, yeah, we can simply drop it on an element like this:

.element {
  aspect-ratio: 16 / 9;
}

…and the element’s default width: auto kicks in implicitly to set the element’s dimensions.

View live demo on CodePen

It changes when width or height are on the same element

Let’s say we have an element with a width of 300px and an aspect-ratio of 3/1.

.element {
  aspect-ratio: 3 / 1;
  width: 300px;
}

By nature, aspect-ratio wants to calculate the element’s dimensions on its own and will do so based on the context where it’s used. But with that width tossed in, it tells aspect-ratio to calculate the element’s aspect ratio box using 300px as the width. As a result, it’s like we’re just written:

.element {
  height: 100px;
  width: 300px;
}

This makes sense! Remember, when no width or height are specified, the browser assumes those are auto and goes from there. When we provide explicit width and height values, those are what get used.

It’s ignored in some situations

This is where things get a little mind-bendy because there are cases where aspect-ratio is overlooked or it’s calculations are affected by other properties. That includes:

When both width and height are declared on the element

We just saw how declaring either width or height on and element will affect the calculation of aspect-ratio. But if the element already has both a width and height, those get used instead of aspect-ratio. It requires both properties to override aspect-ratio; setting either height or width alone will not break the element’s aspect ratio.

aspect-ratio is ignored when both width and height are set on the same element.

Makes senes, right? If using either width or height forces the aspect-ratio to use that value in the calculation, then it logically follows that using both would completely override aspect-ratio altogether since both values are already provided and set.

When content breaks out of the ratio

Simply put, if you have an element with an aspect ratio and the content is so long such that it forces the element to expand, then the element will expand. And if the element expands, its dimensions change and, thus, no more aspect ratio. This is why the spec says the property sets the “preferred” aspect ratio. It’s preferred, but not prescribed.

Don’t like how that works? Setting min-height: 0; on the element will allow the content to overflow the preferred aspect ratio instead of expanding it.

View live demo on CodePen

When it “loses” to min-* and max-* properties

We just sort of saw how that works, right? When content exceeds the dimensions of the box, the aspect-ratio is effectively gone because the box expands with the content. We can override that with min-width: 0.

That’s because all of the min-* and max-* properties typically battle width and height for supremacy in the war over Box Model calculations. For example:

.element {
  min-width: 500px; /* 🏆 Winner! */
  width: 100px;
}

But:

.element {
  min-width: 500px;
  width: 700px; /* 🏆 Winner! */
}

That’s because min-width is either preventing width from going below a specific value, or it is ignored because the width has set already set the element beyond the minimum width it needs to be. The same thing goes for min-height, max-width, and max-height.

The point of all this: if we set both a min-* or max-* property on the same element as aspect-ratio and they “win” over width or height, then those will override aspect-ratio. Told you it was a little mind-bendy. 🤯

Browser support

IEEdgeFirefoxChromeSafariOpera
NoNo86 1.2,390 4TP 5No
Android ChromeAndroid FirefoxAndroid BrowseriOS SafariOpera Mobile
NoNoNoNoNo
Source: caniuse

1 Can be enabled by setting layout.css.aspect-ratio.enabled to true.
2 Support for blocks and replaced elements introduced in Firefox 81.
3 Support for flex items introduced in Firefox 83.
4 Can be enabled by setting #enable-experimental-web-platform-features to Enabled.
5 Available in Safari Technology Preview 118.

More information