Image width based responsive images
By the end of 2013, the average web page served 1,030Kb of images, much to the chagrin of low bandwidth and pay-per-kilobyte users. The need to serve smaller images where appropriate, and to be able to control the scale and crop of images at all sizes, is imperative to creating a light weight and editorially rich web experiences. This is where responsive images come in. Unfortunately, we don't have a standard solution yet, and of those proposed, images will be swapped based on viewport information, not element information. Until we have a standard solution, you've got to pick your favorite hack.
borealis-srcs attribute to your image and you're ready to go!
Installation is super easy. You can either pull down a copy from GitHub here, or you can install from Bower:
bower install borealis --save
Then, add either
borealis.min.js to your HTML, and you're ready to rock!
In order to use borealis, you need to both include
borealis.js on your site and set up the
data-borealis-srcs attribute on your desired image.
data-borealis-srcs needs to be written in
key: value pairs separated by a comma
,, with the key being the
min-width pixel width when you would like to swap out an image and the value being the URL to the image. The first item in
data-borealis-srcs should not have a key and will be the default. In order to prevent extra image requests, do not include the
src attribute in the image definition.
<img data-borealis-srcs="/images/default.jpg, 300: /images/foo.jpg, 500: http://foo.com/bar.jpg, 900: http://qux.com/baz.jpg" alt="Responsive Images powered by Borealis!">
When borealis has determined what size your image is, it will add the appropriate image URL to the image's
src attribute. If the image is smaller than the smallest size, the default will be loaded in. If you did not write your sizes in order, fear not, they will be sorted for you.
borealis also adds
borealis to allow you to utilize borealis in your own function calls. It will handle your
onload event and all
resize events, querying your DOM to determine what nodes need to be queried each time. If you AJAX in any nodes that you would like to query, you need to trigger the query yourself. This is easy though! Just load up your nodes into an array or a NodeList and pass that to
borealis.query(nodes), and borealis will work its magic.
borealis.query() also takes a callback as a second argument with optional
nodes parameter (for the nodes that were worked on) that will be fired once all of the images have been processed.
In order to ensure that borealis is able to work its magic, when the DOM is loaded, all images with
data-borealis-srcs will get
width: 100%; height: auto styling applied to them. To apply these styles to images that aren't loaded on initial load, call
borealis.styleImages(nodes). This will ensure that images continue to grow so borealis can pick up on their width changes while ensuring their aspect ratios stay natural.
borealis neither does any image manipulation nor deals in multi-density image swapping (commonly high-res images). Instead, you need to cut your own images and size them appropriately. Instead of multi-density image swapping, you are encouraged to use compressive images. To further reduce image file size, where appropriate, you should also serve progressive jpegs. borealis does not lazy load images in as the best way to optimize resource loading is to burst data transfer and return to idle.
- Firefox 3.5+
- Opera 10.0+
- iOS Safari
- Opera Mini
- Android Browser
- Blackberry Browser
- Opera Mobile
- Chrome for Android
- Firefox for Android
- IE Mobile
A note on IE8/Older Browser Support
There are three files provided:
polyfills.js just includes the polyfills. While these allow for a drop-in solutions using just what's provided here, a better solution (and where a bunch of the polyfills come from), consider using something like a polyfill service for a more robust and well-rounded solution.
The specific polyfills included are as follows:
Technical Mumbo Jumbo
offsetWidth calculation, which is required for each element; hey, it's an element query after all! Browsers are also super slow at actually painting all of those images, so be aware. We work on reducing read/write layout thrashing by grouping reads separately from writes.
The process for determining which
src to load is primarily greedy for the default, then greedy for the largest size. If the element is neither smaller than its smallest size nor larger than its largest state, it then traverses each size to determine which state is correct. It does this by comparing one size to the next size up, ensuring that the current size is both greater than or equal to the defined
min-width value and less than the next size's
Performance wise, the script handles itself very well even with thousands of nodes. With this current test setup of around 2.2k nodes, it can parse all of the nodes, calculate the size, and apply the proper attributes in about 40ms. We're employing requestAnimationFrame to reduce layout thrashing and produce smooth layout and resize. borealis also comes with the full requestAnimationFrame Polyfill by Erik Möller and Paul Irish.
offsetWidth and image painting are slow,
requestAnimationFrame reduces layout thrashing, borealis is greedy for default then largest sizes, with great power comes great responsibility.