How we test responsive images at Unsplash
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!