CSS has an aspect-ratio
property, which has had full support since around 2021. It can be a very satisfying property to use, because it can help match how your brain 🧠 works or what the desired design outcome does better than forcing dimensions does. “I need a square here” or “I need to match the 16:9 size of a <video>
” are very reasonable design needs. Especially in a fluid environment where you’re purposely trying not to think in exact dimensions because you know they can change.
Usually, It Just Works
Here I’ve got a <div>
sitting in a container. The <div>
naturally fills the width. I’ve set aspect-ratio: 1 / 1;
on it, thus, it’s a square. 🥁
That video example from the intro is also prudent. In that case, for whatever historical reason, <video>
has a default style of being 300px
wide, so if we want it to fill the space, we need to set width: 100%
and then aspect-ratio will do what we want:
Element in a grid will behave nicely as well. Here, 12 <div>s
are placed within a grid with a square aspect ratio and they respect it handily:
But things can go wrong, leaving an element that appears to not respect the aspect-ratio
Potential Breakage #1) Setting Both Dimensions
If both a height
and width
are set on an element, then aspect-ratio
is ignored. That goes for block-size
and inline-size
too, of course, the logical property equivalents.
.el {
inline-size: 300px;
block-size: 200px;
aspect-ratio: 1 / 1; /* does nothing */
}
Code language: CSS (css)
That makes sense to me (which one would it ignore?), but it can be awfully confusing if one of the dimensions is set from somewhere you didn’t expect. Perhaps you were expecting to set a height
and aspect-ratio
on an <img>
, not realizing your baseline CSS file also sets the width
on images, that would make aspect-ratio
fail somewhat unexpectedly.
This can be true of information outside of CSS as well. For example a height
attribute on an <img>
tag (which is highly recommended) counting as the other axis here and not allowing aspect-ratio
to work:
Note that limiting dimensions with min-width
, min-height
, min-inline-size
, min-block-size
, max-width
, max-height
, max-block-size
, max-inline-size
will be respected and also might break the aspect-ratio
.
Potential Breakage #2) Stretching
Here we have three <div>
in a flex container all with different aspect ratios. But… they are all the same dimensions:
Why?! Those <div>
s only have a width
set on them, no height
(or logical equivalent). The problem here is that the height/block-size is forced because flex items are influenced by the default align-items: stretch;
If we change that default to align-items: flex-start;
on the parent flex container, you can see aspect-ratio
start working:
This kind of thing can be true of any of the stretch
values in CSS grid or flexbox. For example, CSS grid has justify-items: stretch
; which is capable of causing this same kind of problem.
Potential Breakage #3) Content That Forces Height
One of the ways we used to pull of aspect-ratio
was Uncle Dave’s ol’ Padded Box Trick. The box would be created by using padding-bottom
on a zero-height box. Percentage padding is a percentage of the width
, so that connection between width and height is established that way. But then you’d put an absolutely positioned box inside that. The problem with absolute positioning here is that the content is outside the normal flow of the document. So if, for example, you put text inside that is taller than the box, you’d have a problem. See below how the content hangs out of the box. The box has the right aspect-ratio, but it’s unlikely this is a desirable outcome:
If we use aspect-ratio
for our box instead, we’ll get:
Now the orange box contains all the content, which again is probably the desired outcome here in most situations. But notably, the box is no longer the aspect-ratio
that we declared.
Did I miss any of the ways aspect-ratio
can break or have unexpected results? I suppose browser-support is another thing to consider, but it’s pretty solid.
Hi Chris thanks. I miss CSS-Tricks
Same. I’ve run into these so many times…”but, aspect-ratio!!!” I yell at the browser, futilely. Thanks for this is a helpful guide to what to look for.
Safari breaks aspect-ratio when applying some animations/transitions to the element. It will look ok at rest and event during the running phase, but after the animation/transition is over, the aspect-ratio will break 😕