By Paul McFedries

When planning a mobile web app, you always need to consider the impact of images, both on your design and on your users.

Making images responsive

On the design side, you need to ensure that your images scale responsively, depending on the screen width or height. For example, if the user’s screen is 1,024 pixels wide, an image that’s 800 pixels wide will fit no problem, but that same image will overflow a 400-pixel-wide screen. You create responsive images with the following CSS rule:

image {
  max-width: 100%;
  height: auto;
}

Here, image is a selector that references the image or images you want to be responsive. Setting max-width: 100% enables the image width to scale smaller or larger as the screen (or the image’s container) changes size, but also mandates that the image can’t scale larger than its original width. Setting height: auto cajoles the browser into maintaining the image’s original aspect ratio by calculating the height automatically based on the image’s current width.

Occasionally, you’ll want the image height to be responsive instead of its width. To do that, you use the following variation on the preceding rule:

image {
  max-height: 100%;
  width: auto;
}

Delivering images responsively

On the user side, delivering images that are far larger than the screen size can be a major problem. Sure, you can make the images responsive, but you’re still sending a massive file down the tubes, which won’t be appreciated by those mobile surfers using slow connections with limited data plans.

Instead, you need to deliver to the user a version of the image file that’s appropriately sized for the device screen. For example, you might deliver the full-size image to desktop users, a medium-sized version to tablet folk, and a small-sized version to smartphone users. That sounds like a complex bit of business, but HTML5 lets you handle everything from the comfort of the <img> tag. The secret? The sizes and srcset attributes.

The sizes attribute is a collection of expression-width pairs:

  • The expression part specifies a screen feature, such as a minimum or maximum width, surrounded by parentheses.
  • The width part specifies how wide you want the image displayed on screens that match the expression.

For example, to specify that on screens up to 600 pixels wide you want an image displayed with a width of 90vw, you’d use the following expression-width pair:

(max-width: 600px) 90vw

A typical sizes attribute is a collection of expression-width pairs, separated by commas. Here’s the general syntax to use:

sizes="(expression1) width1,
    (expression2) width2,
    etc.,
    widthN"

Notice that the last item doesn’t specify an expression. This tells the web browser that the specified width applies to any screen that doesn’t match any of the expressions.

Here’s an example:

sizes="(max-width: 600px) 90vw,
    (max-width: 1000px) 60vw,
    30vw"

The srcset attribute is a comma-separated list of image file locations, each followed by the image width and letter w. Here’s the general syntax:

srcset="location1 width1w,
    location2 width2w,
    etc.">

This gives the browser a choice of image sizes, and it picks the best one based on the current device screen dimensions and the preferred widths you specify in the sizes attribute. Here’s a full example:

<img src="/images/img-small.jpg"
   sizes="(max-width: 600px) 90vw,
      (max-width: 1000px) 60vw,
      30vw"
   srcset="/images/img-small.png 450w,
      /images/img-medium.png 900w,
      /images/img-large.png 1350w">

The sizes and srcset attributes don’t always work the way you might expect. For example, if the browser finds that, say, the large version of the image is already stored in its cache, then it will usually decide that it’s faster and easier on the bandwidth to just grab the image from the cache and scale it, instead of going back to the server to download a more appropriately sized file for the current screen.