As part of HTML5, the srcset attribute for img tags has been specified by W3C to provide an HTML extension for adaptive images. Here's an excerpt from the specification:

When authors adapt their sites for high-resolution displays, they often need to be able to use different assets representing the same image. We address this need for adaptive, bitmapped content images by adding a srcset attribute to the img element.

Why Bother About Adaptive Images?

With high-resolution screens in our smartphones and laptops, we expect our browsers to display crisp images on the web. Because these displays have pixel densities > 1, more pixels are required to render a sharp image with the same relative size. Obviously, those larger images increase the amount of data downloaded by the browser.

The issue with those high-res images is that no optimal solution could be achieved with plain HTML so far. You could pursue one of the following strategies:

Of course, there's a plethora of JavaScript libraries out there which download images with a resolution appropriate for the user's screen. Sometimes, they first download the low-res version of an image and then point the src attribute of the corresponding img tag to the high-res version if on a high-resolution display. They thereby cause browsers to download both images, which is obviously suboptimal because there are two HTTP requests to be made and even more image data to be transferred.

It would be great if browsers decided upfront which version of an image to load. That's where adaptive images come into play.

Making HTML Image Tags Adaptive

Adaptive images are created by adding the srcset attribute to HTML's existing img tags. The src attribute will hold the default image URL which is used when none of the high-res versions specified by srcset will be loaded. This solution is backwards compatible: Old Browsers who don't support srcset yet won't be affected by the additional attribute and will regularly download the image from the URL specified by src.

The syntax required by the srcset attribute is a comma-separated list of so-called image descriptors. Such a descriptor consists of two parts: the image URL and the pixel density of the displays for which that image should be loaded. Here's a simple example of loading an adaptive logo, which has only one descriptor:

Here, the image logo@2x.png will be loaded for displays with a pixel density greater than or equal to 2 (denoted by the 2x after the file name). As you can see, the image file name is suffixed with the pixel density it's made for, which is a common convention. Let's do the math: The image logo@2x.png should be 200px wide and 80px high to be rendered crisply with a relative size of 100px × 40px on a display with a pixel density of 2.

You can simply list all the image descriptors you need (separated by a comma) to provide more than one high-res image version. Here, we're also offering an @3x version:

An HtmlHelper for Adaptive Images

You might have noticed that some parts of the above img tag are quite repetitive and lend themselves to automation. That's what I thought, too, so I wrote a little HTML helper method to emit adaptive img tags. Note that it's based on the convention to append density suffixes like @2x or @3x to the file name.

The ImgTag class implements the IHtmlString interface so that the emitted HTML tag doesn't get double-encoded. Attribute values will be encoded by the TagBuilder.

I didn't want to pass an instance of UrlHelper to the ImgTag class only to access its Content method. Instead, that method is passed as a generic delegate in the constructor (that's the mapVirtualPath function).

If you want to make the code a little more defensive, you should make sure the file name has a proper extension so that LastIndexOf('.') works smoothly.

In the beginning, I had included a few more methods in the ImgTag class to allow for more generic img tags, e.g. including attributes like class. However, these methods are trivial to implement, so I omitted them here for the sake of brevity.