Responsive images with AdaptImages

This light java script provides a simple function, which you can use to support responsive images on your web pages.
Why we need it? Responsive images natively aren't currently supported by web browsers and all available approaches, today, for adapting your pages to show the right size and resolution of images are hacks that compromise on one thing for another. It is important to understand what these compromises are before you pick a particular approach for your next project.

Features:

  • Works well when all images on your page follow the same criteria for selecting the version of an image to show. For example, if a page's width is greater than 640px, show the large version of all images on the page.
  • Is very fast since it only has to test the context once, unlike approaches that must support a different criteria for each image and each source.
  • Works completely client side, unlike earlier similar approaches, which require server side code.
  • Is quite flexible and lets you decide how to choose between versions of images to show. You could use page width, device resolution, matchMedia, observed network speed or any other mechanism to make your choice.
  • Is quite compact, the minified version is ~470 bytes

What this script cannot:

  • Doesn't give you fine grained control on how each image is selected. Approaches that support srcset and media queries for each source are much better if you need that control.
  • As Jason Grigsby points out some browsers, that profess to support javascript, but have poor implementations e.g Blackberry 4.5 has javascript, but javascript cannot manipulate the DOM, these browsers will not get an image with this method.
  • The markup is a semantic mess.
  • The markup isn't future proof. In the future when a standard is implemented for responsive images, you will need to either continue to use adaptImages script or update all old content to support the new picture markup.

Markup

To make an img element adaptable (or responsive) you have to wrap it in a noscript element. This ensures that the wrapped img is only downloaded and used when javascript is not available.
When javascript is available, the adaptImages javascript function uses data-* on the noscript element to insert the correct img element onto the page.
The noscript element must also define data-version attributes, for example data-l and data-s:

<noscript data-s="s.jpg" data-l="l.jpg" data-alt="Red and Blue">
  <img decoding="async" src="s.jpg" alt="Red and Blue" />
</noscript>

The default set of supported versions is ['l', 's'], but your page can override this by defining a data-img-versions attribute on the document's body which takes a space separated list of versions to support.

<body data-img-versions="large small large-2x small-2x">
  <noscript data-alt="Cats"
    data-large="cats.large.jpg" data-large-2x="cats.large.2x.jpg"
    data-small="cats.small.jpg" data-small-2x="cats.small.2x.jpg">
      <img decoding="async" src="cats.small.jpg" alt="Cats" />
  </noscript>
</body>

The noscript element must also define a data-alt attribute, the value of which will be used as the alt attribute of the img that is inserted in place of this noscript.

Script
Once the DOM has loaded, you can call adaptImages with the version you wish to show: adaptImages('l')
A more appropriate example could be: adaptImages(document.documentElement.clientWidth > 640 ? 'l' : 's')
Or if you've defined data-img-versions="large small large-2x small-2x" on the document's body, you could use this to support high pixel density devices, like Apple's Retina display:

var r = window.devicePixelRatio || 1;
var w = document.documentElement.clientWidth;
var s = w > 640 ? 'large' : 'small';
s = r > 1 ? s+'-2x' : s;
adaptImages(s) 

View examples of AdaptImages
Download AdaptImages