Responsive images: DIY implementation in 6 steps
Published: 2023-08-05 23:25:00

## TL;DR

If you as a web developer need to make images responsive to screen widths and device pixel ratios _on your own_, take this 6-step procedure:

**Step 1**: Figure out the maximum width of each image required by the design of your webpage. Let’s say, it is `624px`.

**Step 2**: Convert the original image file into two versions: one with the maximum width (`624px` in our example) and the other with double the maximum width (`1248px`). Image resizing can easily be done with tools like `sips`, a command line tool of MacOS.

**Step 3**: Refer to these two image files with the following _temporary_ `<img>` element:
```html
<img
  sizes="100vw"
  srcset="image1248.png 1248w"
  src="image624.png"
/>
```

**Step 4**: Render the webpage with your favorite browser and click the [RespImageLint](https://ausi.github.io/respimagelint/) bookmarklet. It gives you the correct value for the `sizes` attribute and the widths of additional image files needed to minimize the loading time across all screen types.

**Step 5**: Revise the HTML code by incorporating RespImageLint’s suggestions. In our example, it is something like:
```html
<img
  sizes="
    (max-width: 600px) calc(100vw - 70px), 
    (max-width: 766px) calc(100vw - 141.25px), 
    624px
  "
  srcset="
    image624.png   624w,
    image990.png   990w,
    image1248.png 1248w
  "
  src="image624.png"
/>
```

**Step 6**: Convert the original image file into the ones suggested by RespImageLint, again using tools like the `sips` command line tool of MacOS. Then save them as indicated in the HTML code written in Step 5.

---

Below I elaborate on each step, after a brief explanation of why I’m writing this article.

## Why writing this article?

\[**Feel free to skip this section**: all the sections below are independent of what is written in this section\]

Putting images on a webpage is _hard_. “[T]here are … 927 things you could (and some you really should) do that often go overlooked”, wrote [Chris Coiyer (2021)](https://css-tricks.com/images-are-hard/).

In particular, implementing _responsive images_ is really complicated. You have to think about various screen widths and device pixel ratios in order to decide which widths of each image to prepare for minimizing the loading time.

While many services out there help you automate the generation of responsive image files and the associated HTML code, _what if you have to do it all yourself?_ 

I was recently in such a situation. I tried to find the easy-to-follow procedure of making images responsive with the minimum amount of effort. This article reports what I have arrived at.

There are many articles on responsive images across the web. But, as far as I know, they are all too lengthy, not very helpful for a quick DIY implementation. The closest to this article in spirit is [Archibald (2021)](https://jakearchibald.com/2021/serving-sharp-images-to-high-density-screens/), which proposes “the lazy way” of implementing responsive images. This article intends to improve this “lazy” approach.

## Step 1: Maximum image width

The original image files are most likely to be a lot larger than the size required by the design of your webpage. So the first step is to figure out how large each image file needs to be given the design of your website.

The maximum width of images is usually given by the design for desktop screens. But not necessarily. In the example given by [Archibald (2021)](https://jakearchibald.com/2021/serving-sharp-images-to-high-density-screens/), it is when the screen width is 799px beyond which the images are shrunk to leave side margins.

For the ease of exposition below, let’s say our website design requires the images that are **624px** wide at most.

## Step 2: Image file conversion (Part I)

The second step towards responsive images is to convert the original image file into two versions of it: one with the maximum width (**624px** in our example) and the other with double the maximum width (**1248px** in our example).

The former is for non-retina screens (1x) while the latter is for retina screens (2x), when the user’s screen width requires the maximum image width identified in Step 1.

### Enough to deal with 2x screens only

You might ask, “What about those device pixel ratios (DPR) other than 2x?” As far as I understand, we can ignore them. Here’s why.

[Osmani (2021)](https://www.smashingmagazine.com/2021/04/humble-img-element-core-web-vitals/#device-pixel-ratio-dpr-pixel-density-capping) argues that “[t]he human eye may not be capable of distinguishing the difference between images that are a 2x-3x DPR vs. an even higher resolution.” 

He also reports:
> Twitter capped their image fidelity at 2x, resulting in 33% faster timeline image loading times. They found that 2x was a sweet spot of both good performance wins with no degradation in quality metrics.

For more on this approach adopted by Twitter, see [O'Brien (2019)](https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/capping-image-fidelity-on-ultra-high-resolution-devices).

So we just need to care about 2x screens, even though higher resolution screens are widely available in the market today.

### Image resizing tools

Now the question is how to resize your original images. According to [Hempenius (2018)](https://web.dev/serve-responsive-images/#resize-images):
> Two of the most popular image resizing tools are the [sharp npm package](https://www.npmjs.com/package/sharp) and the [ImageMagick CLI tool](https://www.imagemagick.org/script/index.php).

If you are a Mac user, there is a third alternative: `sips`, which I find very easy to use. [Dachis (2012)](https://lifehacker.com/batch-resize-images-quickly-in-the-os-x-terminal-5962420) explains how to resize image files in a batch by using this command line tool installed in Mac OS by default. Following this article, you can do the following:

1. Make copies of your original image files and save them in a new folder.

2. In Terminal, moving to this folder with the `cd` command. Then execute the following command:
```
sips -Z 1248 *.png
```
which overwrites the original image files and resizes them to the width of 1248px (if the width is larger than the height) without distorting their aspect ratio.

If the height of an image is larger than its width, use the following command instead:
```
sips --resampleWidth 1248 *.png 
```
This is what I have figured out by reading the [documentation of `sips`](https://ss64.com/osx/sips.html).

## Step 3: Draft HTML code
Now write down a draft of the HTML code to embed each image:
```html
<img
  sizes="100vw"
  srcset="image1248.png 1248w"
  src="image624.png"
/>
```

### Temporary `sizes` value
The value for `sizes` is temporary. It’s not easy to figure out the correct value for your webpage design (see [Coyier 2020](https://css-tricks.com/a-guide-to-the-responsive-images-syntax-in-html/#aa-creating-accurate-sizes)). It’s best to rely on an external tool that does all the hard job. That’s for Step 4 below.

### Go with `w` descriptor, not `x` descriptor
The value for `srcset` is also temporary, just including the largest image file at this moment. 

Note that I use the `w` descriptor. As far as I can see, the consensus among web developers is to use `w`, not `x`, for responsive images. Accoridng to [Coyier (2020)](https://css-tricks.com/a-guide-to-the-responsive-images-syntax-in-html/#aa-using-srcset):
> ... [`x` descriptors only account for a small percentage of responsive images usage](https://almanac.httparchive.org/en/2019/media#use-of-html-markup). Why? They only let browsers adapt based on one thing: display pixel-density. A lot of times, though, our responsive images are on responsive layouts, and the image’s layout size is shrinking and stretching right along with the viewport. In those situations, the browser needs to make decisions based on two things: the pixel-density of the screen, and the layout size of the image. That’s where `w` descriptors and the `sizes` attribute come in ...

### Use `src` for a fallback image file
Finally, the `src` attribute refers to a fallback image file in case the user’s browser does not support `sizes` or `srcset` attributes.

In which width should the fallback image file be? I cannot find any tip on this (please post a comment if you know any). My own reasoning concludes that the 1x screen version of the maximum width (**624px** in our example) is good enough. Here's why:

The legacy browser that does not support sizes or srcset is likely to come with either the 1x desktop screen or the 320px-wide 2x screens of iPhone 4 and iPhone 5.
- The first 2x screen was released with iPhone 4 on June 24, 2010 (source: [Wikipedia](https://en.wikipedia.org/wiki/IPhone_4)). 
- The iOS Safari first supported `sizes` and `srcset` with its version 9, released on September 16, 2015 (source: [Can I Use?](https://caniuse.com/srcset)). That was when iPhone 6 was released (source: [Wikipedia](https://en.wikipedia.org/wiki/IPhone_6)).
- The screen width of iPhone 4 and iPhone 5 is 320px (source: [Wikipedia](https://en.wikipedia.org/wiki/Retina_display)).

Consequently, the fallback image file should cater to iPhone 4 and iPhone 5’s 320px wide screens, which require an image width of 640px at most.

If the maximum image width is less than 640px, you may want to use a 640px-wide version as a fallback. Otherwise, the maximum image width is sufficient.

### How `sizes` and `srcset` work
If you need to brush up your understanding of how `sizes` and `srcset` attributes work in tandem, I recommend [Portis (2018)](https://observablehq.com/@eeeps/w-descriptors-and-sizes-under-the-hood) and [Google Developers (undated)](https://web.dev/learn/images/descriptive/#describing-usage-with-sizes), both of which clearly explain how browsers choose which image file to use based on the information given by the `sizes` and `srcset` attributes.


## Step 4: RespImageLint

The fourth step is to obtain the optimal values for `sizes` and `srcset` attributes with the help of [RespImageLint](https://ausi.github.io/respimagelint/), a bookmarklet developed by Martin Auswöger.

[Coyier (2020)](https://css-tricks.com/a-guide-to-the-responsive-images-syntax-in-html/#aa-creating-accurate-sizes) explains what RespImageLint does succinctly:
> Martin Auswöger’s RespImageLint ... programmatically resizes the page a bunch and writes out a `sizes` attribute that describes the actual, observed width of the image over a wide range of viewport sizes. It’s computers, doing math, so it’s right. So, if you want a super-accurate sizes attribute, I’d recommend just putting a wrong one on at first, running this tool, and copying out the correct one.

Plus, RespImageLint gives us the recommended value for `srcset`.

Given these suggested values, we can now revise the HTML code written earlier in Step 3.

## Step 5: Revise HTML code
In our example, RespImageLint suggests the following:
```html
<img
  sizes="
    (max-width: 600px) calc(100vw - 70px), 
    (max-width: 766px) calc(100vw - 141.25px), 
    624px
  "
  srcset="
    image624.png   624w,
    image990.png   990w,
    image1248.png 1248w
  "
  src="image624.png"
/>
```
See the value of `sizes`. To get it right on your own, you have to go through the entire CSS style sheets back and forth. It’s best to rely on the automation provided by RespImageLint.

For `srcset`, RespImageLint suggests the image widths of not only 624px and 1248px but also 990px. This additional image targets 2x mobile screens in the range of widths between...(let me do the math for you)...382px and 565px. Without this image file, these mobile devices would have to download the 1248px image whose file size is way bigger than necessary.

## Step 6: Image file conversion (Part II)
The last thing we need to do is to convert the original image file into those suggested by RespImageLint and match the file paths for the converted images with the ones specified in the HTML code written in Step 5.

Now you are done for responsive images!

---
But there are a few other things to do for images. For a reminder, see the list in [Coyier (2021)](https://css-tricks.com/images-are-hard/). 

In particular, the above HTML code for `<img>` misses the `alt` attribute. I once spent the whole day to figure out how to write the `alt` text properly. See my blog post, [Kudamatsu (2021)](https://dev.to/masakudamatsu/mastering-the-art-of-alt-text-for-images-2900), for what I have learned.

## Changelog
**Oct 1, 2023 (v1.1.0)**: Add a paragraph on resizing an image file with sips when the image's width is shorter than its height.

## References

Archibald, Jake (2021) “[Halve the size of images by optimising for high density displays](https://jakearchibald.com/2021/serving-sharp-images-to-high-density-screens/)”, _jakearchibald.com_, Jun 11, 2021.

Coyier, Chris (2020) “[A Guide to the Responsive Images Syntax in HTML](https://css-tricks.com/a-guide-to-the-responsive-images-syntax-in-html/)”, _CSS-Tricks_, May 26, 2020.

Coyier, Chris (2021) “[Images are hard.](https://css-tricks.com/images-are-hard/)”, _CSS-Tricks_, May 26, 2020.

Dachis, Adam (2012) “[Batch Resize Images Quickly in the OS X Terminal](https://lifehacker.com/batch-resize-images-quickly-in-the-os-x-terminal-5962420)”, _Lifehacker_, Nov 21, 2012.

Google Developers (undated) “[Learn Images! — Descriptive syntaxes](https://web.dev/learn/images/descriptive/)”, _web.dev_, undated.

Hempenius, Katie (2018) “[Serve responsive images](https://web.dev/serve-responsive-images/)”, _web.dev_, Nov 5, 2018.

Kudamatsu, Masa (2021) “[Mastering the art of `alt` text for images](https://dev.to/masakudamatsu/mastering-the-art-of-alt-text-for-images-2900)”, _Dev Community_, May 19, 2021.

O'Brien, Nolan (2019) “[Capping image fidelity on ultra-high resolution devices](https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/capping-image-fidelity-on-ultra-high-resolution-devices)”, _Twitter Engineering_, May 9, 2019.

Osmani, Addy (2021) “[The Humble `<img>`` Element And Core Web Vitals](https://www.smashingmagazine.com/2021/04/humble-img-element-core-web-vitals/)”, _Smashing Magazine_, Apr 29, 2021.

Portis, Eric (2018) “[w descriptors and sizes: Under the hood](https://observablehq.com/@eeeps/w-descriptors-and-sizes-under-the-hood)”, _Observable_, Mar 28, 2018.