The src-N Responsive Image Solution

by Christopher Schmitt

Amidst the discussion of the two most popular responsive image solutions that have been proposed to be included within the HTML specification, a new proposal entered the discussion — the `src-N` attribute.

This attribute, proposed to be included within the `<img>` tag, promises to deliver a complete solution in a way that `srcset` and the `<picture>` tag cannot.

Why should we replace `srcset` and `<picture>`?

Use cases:

There are three standard use cases in which a responsive image solution is supposed to be employed:

1. Device pixel ratio based resolution switching: Devices with a higher pixel-density (which support 2 image pixels per CSS pixel) should load a higher-quality image than lower-pixel density devices.

2. Viewport size based resolution switching: Devices with a smaller viewports (or layouts with smaller column-widths) should load images with a smaller resolution than devices with larger viewports.

3. Art direction: Different images altogether might be appropriate on different displays. A large image with lots of detail may be appropriate on a desktop screen, but would look too small and cluttered on a mobile device. You may want to serve up a cropped image (or different image altogether) on a smaller screen.

A responsive image solution that successfully navigates these use cases conserves bandwidth and serves up the image that looks best on the user’s device and within the current layout. A solution that cannot handle these three use cases can result in a page that loads slowly, or with images that break the layout or lack sharpness.

Unfortunately, the two popular proposed solutions, the `srcset` attribute and the `<picture>` element, can handle one or two of the use cases, but neither can handle all three. `srcset` can’t handle the art direction case (nor can it completely solve viewport switching). The `<picture>` element can’t handle viewport switching –at least, not without including a lot of breakpoints within the syntax along with repetition of image URLs<sup>1</sup>.

The `srcN` attribute has a versatile syntax that can arguably handle all of the use cases in an elegant fashion. It can put the burden upon the user agent to figure out which image best suits the viewport and resolution, relieving the coder of having to manually calculate a series of breakpoints with their accompanying images.

The syntax

The `src-N` solution is an iterative attribute that applies to the standard `<img>` tag. The attribute label is comprised of “src-” and a number (so, `src-1`, `src-2` and so on), where each `src-N` attribute corresponds to a single media query. A complete `<img>` tag that includes a series of `src-N` attributes looks something like this:

<img src-1="(max-width: 480px) pic-phone.jpg"
                   src-2="(max-width: 1024px) pic-tablet.jpg"
                 src="pic-desktop.jpg"
                 alt="The picture description.">

Here we have two `src-N` attributes. The media query (in parentheses) defines our breakpoints. `src-1` specifies a photo (perhaps a cropped photo) for smartphones. `src-2` loads a medium-sized photo for tablets. The final image URL is the value for the standard `src` attribute. This, the largest image, which loads on desktops, and works as the fallback image if the user agent doesn’t support `src-N`.

Grammar

Let’s dig in to the syntax a bit more. The grammar, while versatile, is a bit involved, so let’s go through the grammar proposal line by line:

<src-n-attribute> = <media-query>? [ <x-based-urls> | <viewport-urls> ]

The media query, which is optional, is formed like any other CSS3 media query–where the device is targeted by media features such as a minimum or maximum width. After the media query (if included) you specify your image URLs, which can either be resolution-based (x-based) or viewport-based.

Resolution-based URLs

Resolution-based URLs are used when we want to load a higher-quality image for devices with a higher pixel-density, and lower-quality (bandwidth-saving) images for standard displays:

<x-based-urls> = [ <url> <resolution>? ]#

Resolution is expressed as the ratio of image pixels to CSS pixels. So, a high-pixel density device, which is 2 image pixels to 1 CSS pixel, would be expressed as 2x. List the URLs as comma separated values, e.g.:

<img src-1="standard.png, high_density.png 2x">

The first image would load on standard displays, while the high-density displays would load the second image.

Viewport-based URLs

Viewport-based URLs require the most complicated syntax. This complexity is due to the fact that, within a layout, image sizes are often specified as percentages, rather than distinct pixel sizes. Consider the following CSS:

img {
            float: left;
            width: 50%;
      }
 
      @media only screen and (max-width : 30em) {
            img {
                  width: 100%;
            }
      }

Here we have the image size expressed as a percentage: 50% wide columns on a desktop, and 100% on smartphones.

It would be ideal if we had several images of varying widths, and the user agent decided which is most appropriate for the circumstance. So, an intelligent responsive design solution would take into account:

1. The viewport sizes: In our example (1) 30em for smartphones, and (2) everything above that
2. What size the image should be for each viewport size – In our example: (1) 100% and (2) 50%
3. The list of image URLs, along with their respective lengths, in pixels.

Knowing all of the information, a user agent should be able to calculate which of the listed images it should load. For example, a very large image for a large Apple retina display, or the smallest image for an old iPhone, in portrait mode.

So, any piece of syntax that would capture all of this information would be understandably long-winded.

Thus, the grammar for viewport-based URLs is proposed as the following:

<viewport-urls> = <size-viewport-list> ; <size-based-urls> 
      <size-viewport-list> = <image-size> [ ( <viewport-size> ) <image-size> ]*
      <image-size> = <length> | <percentage>
      <viewport-size> = <length>
      <size-based-urls> = [ <url> <integer> ]#

Our example above would then work out to look like:

<img src-1="100% (30em) 50%;
             x-small.png 200, small.png 500, medium.png 800, 
             large.png 1100, x-large.png 1400">

Note that, using this solution, both a high-pixel-density smartphone and standard desktop might load the same medium-sized (800 px) image. While the attribute declaration can get a bit convoluted (especially when working with multiple viewport sizes), this is notably more efficient than manually calculating the appropriate image size for various breakpoints, screen sizes and screen resolutions.

The `src-N` responsive image solution aims to handle all three use cases elegantly. In exploring it’s rather complex syntax, we can see that it can deliver a lot more data to the user agent than `srcset` and the `<picture>` tag. Using this additional data, the user agent can more accurately calculate which of the specified images is best fit the user’s circumstance.

Check out the proposal for this solution (drafted just last month).

1. For a more complete explanation of the three use cases and the justification for `src-N`, check out these following three resources; resource 2, and resource 3.

For more complete information about compiler optimizations, see our Optimization Notice.