Imager.js (BBC News responsive images solution)

Introduction

Previously Tom Maslen wrote a quick summary of the responsive image loading strategy used by BBC News. This post resulted in a lot of interest from the development community and so we wanted to follow up with another quick post which explored in more detail the actual implementation of this approach.

Addy Osmani from the Google Chrome team recently contacted us to express his interest in the technique we are using and so we decided it would be a good idea to go the open-source route and release a version of our approach so the developer community could benefit from an alternative solution to the responsive image problem (especially considering the pre-existing proposed specifications for 'srcset' and the 'Picture' element aren't yet widely implemented and the currently available polyfills aren't quite up to scratch yet either).

The original code was written back in 2011 (and was also heavily tied into the BBC infrastructure) so the first thing we needed to do was rewrite the code so it could more easily be understood and then we could start work on open-sourcing it and improving it.

Moving forward we aim to collaborate further with Addy and the rest of the community on getting the process automated using the popular front-end JavaScript task runner Grunt.

What's the gist?

It's pretty simple really…

  1. Wherever you want an image to appear you use a <div>
  2. You give it a class and data-src, data-width attributes
  3. Load and run the Imager.js code (we use a predetermined list of image sizes, but these are specific to BBC News and so can be changed to match your own requirements)
  4. Imager replaces the div's with a transparent 1x1 Base64 encoded image.
  5. Imager then replaces those with the most appropriately sized image (based on the current image and the user's screen dimensions and see if they correlate to our list of available image sizes).
  6. Imager set-ups a resize event listener to check whether the image needs to be replaced with another more appropriately sized image.

…fundamentally, that's it.

Anything more technical you can tell us?

The way we determine what size image to place onto the page is by taking the current screen width and then looking at the 'rendered' size of our image (using myImageElement.clientWidth). We then check if the rendered image size approximately matches one of the sizes available in our predefined list of image dimensions. Once we have a match we then parse the current image URL (which if using a RESTful format would look something like http://your-image-service.com/horse/100/ -> and would return an image of a horse 100px wide), finally we replace the width in the URL with the new replacement width and update the image source to load that more appropriately sized image based from the new RESTful URL we set as the image source.

The code for Imager.js is quite small and pretty self explanatory (considering the break-down of the process listed above), so rather than me repeat the code line for line just take a look here.

So it's open-sourced and ready to use right?

It's open-sourced https://github.com/BBC-News/Imager.js/ and is usable but it currently relies on users having their own RESTful image service.

For the purpose of providing a simple demonstration we used the 3rd party service Placehold.it.

What's left to do?

Well, there are many things we want to do with Imager but the next step is to try and automate the process using Grunt and to supply a simple server-side script that helps users experiment with the code more easily.

But the beauty of the open-source community means we've already had a member of the Yeoman team contributing code that helps cache the generation of images, as well as improve performance by replacing the use of setTimeout with a polyfill for requestAnimationFrame (not to mention some other small refactorings).

Conclusion

Here at BBC News we have found this approach provides us a good flexible foundation to incorporate responsive images without resorting to un-stable and un-implemented official solutions or polyfills.

Is this the best solution available today? Unlikely. But the more choice developers have at their disposal the better.

If you have any questions then feel free to open an issue on the Imager.js GitHub repo.


Links