Creating an aspect ratio CSS utility

Categories

Until we get a native aspect ratio unit in the browser: achieving a controlled height based on a container’s width might seem difficult in a responsive design at first glance. It is actually pretty darn trivial, thanks to good ol’ padding and a touch of positioning magic (read: hacking).

The utility’s code permalink

We’ve got a two for the price of one going on here:

Code language
CSS
[class*='ratio-'] {
  display: block;
  position: relative;
}

[class*='ratio-'] > * {
  display: block;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

.aspect-ratio-wide {
  padding-top: 56.25%;
}

.aspect-ratio-square {
  padding-top: 100%;
}

🔥 Pro tip: The [class*=''] selector looks for elements that contain whatever you put in the quotes. It’s handy for querying parts of a selector when you’re not 100% sure of an element’s construction.

We’ve got two separate classes that specify a ratio and then a shared bit of CSS that is common to both.

The .aspect-ratio-* class creates a relatively positioned container because its direct descendant is absolutely positioned. Adding a top padding value of X% means that the container will have X% of its own width as vertical padding.

This padding value is the magic of the aspect ratio utility, because no matter how wide or narrow the container gets, the height will always be relative to its width. It’s a tidy little CSS algorithm.

The absolute positioning serves two purposes, too: it makes it easier for the child element to fill its container—but more crucially—it prevents that child element from affecting its parent’s padding.

Examples permalink

This utility is flexible and can be used in a number of contexts. Here’s two common ones.

Image gallery

Sometimes it’s handy to render out a list of square images in a grid. We all know images can vary in size, so the mixture of .aspect-ratio-square and some object-fit gives you exactly what you want, with a tiny amount of CSS (even to generate a completely responsive grid).

This is thanks the the .aspect-ratio-square utility having a padding-bottom value of 100%, which is what makes it a perfect square.

Video embed

One thing that can be a bit of a head scratcher is responsive video embeds. Not with the ratio utility, though!

If you add .aspect-ratio-wide to the container of the <iframe>, it adds a bottom padding value of 56.25%, which gives you a 16:9 aspect ratio, regardless of width. The CSS also takes precedence over the width and height attributes, which you can still use to set sensible defaults for if your CSS fails. Progressive enhancement in action.

Wrapping up permalink

With only a few lines of CSS, we’ve got a handy little CSS algorithm that gives us aspect ratio. It’s frustrating that we’re having to use absolute positioning within the utility, but that won’t be the case forever because that magic aspect-ratio unit is only around the corner.

When it arrives, we’ll be able to extend this utility to use the new aspect-ratio unit as a progressive enhancement. Until then, you can read the draft spec in preparation.

Hello, I’m Andy and I’ll help you build fast, accessible websites & design systems.

I’m a freelance CSS and design systems consultant, based in the UK. I specialise in design systems and creative web design, such as landing pages and campaign work.

I’m currently helping Google by refactoring the CSS and creating a design system for web.dev, but I have availability for projects such as small websites, landing pages and consultancy. I will have full availability for larger projects in January 2022.

Hire me