Some things about responsive images

Let’s start by introducing some of the HTML/CSS you’ll find when dealing with images.

The <img> tag: The most common and probably easiest option for displaying an image. It’s a tag you’ve probably seen before.

Use the src attribute to link to the image you’d like to show. But you can also use srcset and sizes to specify responsive images. More on that later.

<img srcset="elva-fairy-320w.jpg 320w,
             elva-fairy-480w.jpg 480w,
             elva-fairy-800w.jpg 800w"
     sizes="(max-width: 320px) 280px,
            (max-width: 480px) 440px,
            800px"
     src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy">

The alt attribute: Used by screen readers and web crawlers to describe the image in case it doesn’t load. Important for the accessibility of your site: screen readers will read out this text. Use a full description of the image instead of something like “image”.

The <figure> tag: Figures are used to group accessories for an image, like captions, code blocks, tables, or video. This avoids having to wrap the picture in <div> blocks.

How to use: wrap your element in <figure> tags, and then optionally add the extra things, like a <figcaption> to add a caption.

<figure>
  <img src="mundane_picture.jpg" alt="Amazing picture that would amaze you if you saw it. ">
  <figcaption>Change your life with this amazing picture.</figcaption>
</figure>

Note you can have multiple images in one figure.

The <pre> tag: Stands for preformatted text; use to display the text as-is between the tags. Usually displayed in a monospaced font like Courier.

The <code> tag: Put any code you’d like to show on your webpage between these tags.

Here is an example of some code between <figure> tags, with a caption.

<figure>
  <figcaption>Your code title</figcaption>
  <pre>
    <code>
      <!-- your code here -->
    </code>
  </pre>
</figure>

The <picture> tag. Basically serves as a decision tree for images, deciding which one to load. Doesn’t do image optimisation, that’s what <img> does. See below.

The <source> tag: Works with the picture tag to let you you choose between alternate media resources (like images or music) depending on certain conditions.

Here’s a query using the width of the screen to decide what picture to load.

<picture>
	<source media="(min-width: 800px)" srcset="pic-big.jpeg">
	<source media="(min-width: 400px)" srcset="pic-small.jpeg">
	<img src="pic-tiny.jpeg" alt="A horse dancing erratically.">
</picture>

The first source condition that is matched will be used.

The type attribute: This looks something like <source type="image/webp" srcset="pic.webp”>. The purpose of this attribute is to tell the browser what kind of file is inside the source tags.

This is useful because if browser doesn’t support the file type, it won’t download the file. Without this attribute the browser would first download the file and then see if it could use it or not. By including type information you’ll save your users some space with downloads.

Two image problems Link to heading

There are two common problems with displaying images to users. These are called art direction and resolution switching.

The first problem is one called art direction. If a user is on a big desktop screen, or a small mobile phone, should they see the same image? Or should the mobile user see a more cropped version of the image? Images should be changed depending on what display is used.

Look at this dog below.

four devices showing art directed crops of a dog.

The large screen shows the full image, while smaller screens show more of the dog and less of the background. This makes sense because the dog is the important part of the picture. You wouldn’ t get this effect if you just scaled down the image.

How do you get this effect? Use media queries on a <picture> tag to specify when to load each image.

<picture>
  <source media="(max-width: 799px)" srcset="doggo-closeup.jpg">
  <source media="(min-width: 800px)" srcset="wide-screen-doggo.jpg">
  <img src="wide-screen-doggo.jpg" alt="Dog posing in front of roses and white mansion,">
</picture>

All cropped images should be of the same underlying picture, meaning you’ll only use one <alt> tag to describe all the images.

The second problem is resolution switching. This is when you have the same image, but at different resolutions.

Why do you need different resolutions for the same image? As always, it comes down to the user. Some browsers specify they prefer low-resolution images; perhaps to save data, or because their display is low density. Sometimes the user has a small screen and they need a smaller, non-cropped version of the original image. Or another user might have a really good new smartphone, with a very good display, and they need a high resolution image to look good on that display.

You solve the resolution switching problem by providing a number of appropiate images, so that the browser can download the optimal one for each user. But: this only works for <img> and the srcset and sizes attribute. It doesn’t work for <picture> and media attributes, like we used to solve the art direction problem.

To summarise, art direction refers to cropping images. You’ll end up with a number of cropped versions of the same image, each used for a different screen size. Resolution switching doesn’t crop images, but has different versions of the same image, each with a different size or resolution.

Using srcset and sizes Link to heading

You may have noticed we used the <picture> element above to choose what image to display.

There’s another method: using srcset and sizes. Why would you want to use this?

Quoting this answer from Stack Overflow:

The <picture> element (and <source> sub-elements) are the heavy guns you bring in when you want to do art direction on different sizes / aspect ratios of the image. The img srcset attribute is much more lightweight and is all you need if you want to design for different resolution displays.

Using srcset comes in two parts. Step one is to create the images. Step two is to write the srcset markup.

You want four sizes of each image: a base one, one 2x the size, one 3x the size, and one 4x the size. You can modify them in a few ways: cropping out bits, making the image proportionally smaller, or with more compression.

You’ll create

  • image-1x.jpg
  • image-2x.jpg
  • image-3x.jpg
  • image-4x.jpg. Either your original image, or the largest image that you want to put on your site.

Note this doesn’t apply to SVG files, since they look good independent of your browser size and resolution.

Writing srcset Link to heading

There’s two common ways you can write this.

Specifying image density: using 1x, 2x etc after your file names

<img srcset=" 
	/image-4x.jpg 4x,
	/image-3x.jpg 3x, 
	/image-2x.jpg 2x, 
	/image-1x.jpg 1x " 
src="/image-1x.jpg" >

Specifying image width: write the width of each file with w as the suffix.

<img srcset=" 
	/image-4x.jpg 4025w, 
	/image-3x.jpg 3019w, 
	/image-2x.jpg 2013w, 
	/image-1x.jpg 1006w " 
src="/image-1x.jpg" >

Writing sizes Link to heading

sizes does the following:

  • specifies how wide the slot for the image should be in our layout.
  • specifies what images to load, based on a media condition like how wide the device is. This won’t make sense for all use cases. If you have a small image slot, you wouldn’t load a big image, even if the viewport is large.

A simple(ish) example with sizes:

 <img
     sizes="100vw"
     srcset="small.jpg 400w, medium.jpg 800w, large.jpg
     1600w"
     src="fallback.jpg"
     alt="...">

The 100vw means this image is 100% of the viewport width. Images will be bigger for laptops and smaller for smartphones.

Here’s another example (from here) with both sizes and srcset together:

<img srcset="elva-fairy-320w.jpg 320w,
             elva-fairy-480w.jpg 480w,
             elva-fairy-800w.jpg 800w"
     sizes="(max-width: 320px) 280px,
            (max-width: 480px) 440px,
            800px"
     src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy">

sizes works well with srcset if you specify your images with w at the end. What happens is that the browser figures out through sizes how wide the slot for the image is. Then it looks at the srcset to figure out what would be the best image to load.

You can get help to write sizes: use https://ausi.github.io/respimagelint/ or other tools.

Remember: Browsers choose their own image Link to heading

Despite all the work you put into optimising srcset and sizes, you aren’t commanding the browser to use an image. You are just suggesting some candidates, and the browser makes its own decision on what image to show.

Here are some factors that might influence the decision:

  • the average internet speed of the current session
  • the preferences of the user (e.g. data saver mode on Chrome)
  • caching. If the user has a bigger image already cached, it won’t request the smaller one; it can just rescale the larger to the smaller one. If the user has a smaller image cached, the browser will request the bigger one; it won’t want to stretch the small image because it’ll look grainy.

References Link to heading

Image Performance - Mat Marquis
MDN docs on Responsive Images