Responsive Pictures without Reflow

Back in the day reserving space on a page for an image was easy, just add the width and height attributes! Then along came responsive designs, and that all kinda went out the window, because you see the browser didn’t know how to reserve space for an image with max-width: 100%; height: auto;. That meant the janky reflow of the image loading was back, without a simple generic solution to solve it.

That never sat right with me, so for today’s posts I’m going to explore the possibility of a generic solution, and what browser vendors are planning to do to make this easier.

Creating a generic solution

Aspect Ratios

In theory, reserving space for an image with a known original width and height should be simple, just calculate the aspect ratio and apply it to the responsively computed width to get the height (or vice versa). Unfortunately browser don’t currently do this, and aspect ratio CSS proposals have yet to land, but more on this later.

That being said, most skilled front-end web developers know there is a trick for creating aspect ratio boxes, using a odd but useful design choice in the way the CSS spec computes padding. If you’re not yet familiar with the so-called aspect ratio boxes trick, you should definitely read that article first.

Putting it all together

So we know an aspect ratio constrained box is definitely possible, so how can we use it to responsive images, how can we take it to the next level and add responsive text captions beneath it?

Well, as it turns out, with just a few elements and some CSS (made with PUG and SCSS in my case), it’s totally possible!

I now present to you my latest CodePen (click the link to view it on CodePen and try resizing and reloading the page to see it all in action):

Here’s the basic steps to get it working:

  1. Wrap the img tag in another tag (picture is a good tag for this) which is our aspect ratio box (which we can use calc() to calculate for us automatically), positioned to fill the aspect ratio box.
  2. Wrap that box in another element (.picture-content) which is set to display: table-cell, with the width style set to the default image width (if you want to link the image somewhere, this can be your a tag).
  3. Finally wrap that element with a display: table element (.picture, which can be a semantic figure tag).
  4. Optionally, add a display: table-caption; caption-side: bottom; element (.picture-caption) with any caption desired.

It does require writing the width and height for the image a few times, but unless you are writing static HTML pages you’re probably going to generate the HTML procedurally anyhow. Additionally, if you only support browsers with CSS variable support, you can take it to the next level and just set the width and height from inline variables inherited from the outer element. This could also be treated as a progressive enhancement where only those browser which support CSS variables get the benefit of avoiding the janky reflowing.

I’m surprised this doesn’t appear to have been proposed before as this doesn’t even require newer CSS features to accomplish. All modern browser and many ancient browsers are supported, it even works in IE 9 and if you pre-calculate the aspect ratio so you don’t use calc it should even work in IE 8 (not that you should care about that at this point).

The Future

In the future, you won’t even have to do all this. Firefox 71 just shipped a new feature where an image’s width and height attributes are finally used to compute the aspect ratio of the image as it loads. Chrome is expected to also ship a similar feature soon. Assuming Apple also adds such a feature, all major browser should soon make all of this much simpler.