Update 2: this technique – the padding box aspect ratio – is featured in Ethan Marcotte’s excellent book Responsive Design: Patterns & Principles.
Update: My good friend Russ made a JS Fiddle of this. Check it out! https://jsfiddle.net/russbeye/kg4ktay8/
More than any other single problem, Responsive images illustrate *why* front end design is so difficult.
Responsive Images have too many solutions
There are a ton of solutions to responsive images, and this is one of the giant problems with figuring out how to solve them.
Here are some of the common approaches:
- width: 100%; height: auto;
pictureelement and a polyfill)
- background images (which have long had better support for some features)
These all have use cases and none are “better” than the other. When making front end design decisions, it always comes back to what’s right for this project, which always starts with understanding the content of the project.
However, an approach that enjoys a lot of support and solves a lot of problems is one we use a bunch at Spry.
We call this an aspect-ratio first approach.
Just to refresh you: aspect-ratio is the width of an image over the height of an image. All screens have an aspect ratio, and the math of a ratio is easy to communicate across disciplines. The Creative Director, Art Director, or Designer and I will talk through picking the aspect ratios we want to maintain in the design. Some of the common ratios out there are:
Panoramic – 21:9 (42.857%)
Widescreen – 16:9 (or 4:3, 56.25%)
Thirds – 3:2 (66.667%)
Landscape – 8:5 (62.5%)
The coding here is pretty simple (another benefit). For markup, we’re going to start with the
figure element This tells any screen readers that there’s a visual element here, and also gives us the option to pass in whatever we want. Inside of the
figure element, we’ll have a wrapper
div and for this example we’ll have a
div with a
background-image. Like I said, background images have wide support and really good features like background size, background position, background blend mode, repeat, and more. It also lets us do things like add text over the image without extra markup.
Next, we’ll create a few classes in our .css to achieve the effect.
First, we’ll set a width of 100% on the wrapper, and we’ll set the position of this wrapper to relative.
For the div inside of the wrapper, we’re going to set it position: absolute, and top:0; left:0; bottom:0;, and right:0;. To make our lives easy, we’ll set background size to cover too – this will pull the image to “cover” the div, which is now absolutely sized to the 4 sides of the wrapper. If we need to add text styles, like, making it white text so it will show up on a dark background, we can do that here too, but if it’s just the image, it’s not necessary.
Here’s the trick: padding is always calculated based on the width of the element. Which means we can set a % value of padding-top or padding-bottom, and this will always set the height relative to the width. Which is *exactly* the concept of the aspect ratio. Because we might be using different aspect ratios, I like to set classes for each of the aspects I noted above. Which means adding an aspect ratio is as simple as adding a class to this display pattern. This is more code up front but better scalability later because I don’t have to reinvent the wheel or come up with a new clever name. It’s treating the job like a prep chef instead of a diva.
<div class=”aspect-wrapper landscape-aspect” >
<div class=”aspect-image” style=”background-image:url(insert the url of the image here);”></div>
I like to write this with the background image styled inline, because then I can pass it’s url in as a variable using php or whatever the templating language is, or just because I’m probably not using the same image for each instance of this pattern.
This allows our image to always maintain the same aspect ratio (e.g. no weird cropping, no losing focus, etc) no matter what. As solutions go it is robust, reusable from project to project, and allows lots of control over art direction.
Hope it helps!