How we test responsive images at Unsplash

Oliver Joseph Ash
Unsplash Blog
Published in
3 min readJun 8, 2018

At Unsplash, one very common problem we have to deal with is responsive images. How can we serve appropriately sized images to the vast variety of devices that visit our website — for all types of screen sizes, device pixel ratio, and so forth?

To solve this problem, we use a mixture of the img element with its srcset and sizes attributes along with the picture element. In our experience, however, the hardest part in getting this right is meticulously finding the correct values for the img sizes attribute. Once we've done that, we want to write tests for it, to ensure it stays in sync with the image's actual size in the page layout. In this article we'll review the approach we took at Unsplash in order to do this, which is facilitated by a small module we wrote called responsive-image-test.

Responsive images recap

The img sizes attribute tells the browser how wide an image will appear for all media conditions (namely window width), so that it can then use this information to download the closest matching image source—from the source set (srcset attribute)—according to its width descriptor. (The browser can't work this out for itself because it needs to start downloading images before it starts laying out the page.)

In this example, the sizes attribute tells the browser that this image will be 200px wide on screens smaller than 500px, and 300px wide on screens equal to or larger than 500px. The browser then uses this information, together with the current device pixel ratio, to pick the most suitable image source from the srcset attribute.

Testing responsive images

In order to make sure we’re serving our responsive images efficiently, we need to take extra care to make sure the sizes attribute is accurate, in that it should reflect the size of the image in the page layout.

Deciding what value to use for srcset isn't so difficult. We can simply provide a set of images on a spectrum of small to large widths.

We want to ensure our sizes continues to stay in sync with the page layout. If a change to the page layout effects the image size, we will need to update the sizes attribute to reflect this. For example, our sizes may specify an image on desktop will always be 300px wide, but a layout change means it is now 400px wide. Ideally, if we forgot to update srcset alongside any layout changes, our tests would fail and serve as a reminder to update it.

In order to test our sizes attribute, we programmatically spin up a browser using tools such as Puppeteer or Selenium, and then run a series of assertions for each image we want to test.

Firstly, we navigate to the website. For example, in Puppeteer:

Next, we perform any test setup such as resizing the window.

Next, we parse the sizes attribute to calculate the current value. For example, given a sizes attribute of (min-width: 500px) 300px, 200px, if our window width was 600px, the current value after parsing would be 300px. This is achieved using parse-sizes, evaluating any calc expressions in the result, and then reading the computed value.

Finally, we can assert that the parsed value from the sizes attribute (parsedSize) equals the image's actual width (elementWidth).

Our getAllImageSizes function also returns the width of the image's current source (currentSrcWidth), which would be helpful if we wanted to test we had a well defined srcset. For example, we could assert that the current source width is approximately equal to the image's actual width.

We have also found these helpers to be useful in development, by observing and logging the size values as they change, e.g. on resize:

In practice, here is what that looks like:

You can try this out now on your own responsive images by importing the responsive-image-test module we wrote, which bundles the code demonstrated above.

If you’re interested in following a similar approach, you may be interested in our responsive-image-test module.

If you like how we do things at Unsplash, consider joining us!

--

--