/borealis

Element query based responsive image solution

Primary LanguageJavaScriptMIT LicenseMIT

Borealis Build Status Coverage Status Code Climate Bower version

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.

Based on the blazing fast and light weight eq.js, borealis provides a bare-bones image width based responsive image solution. Designed as a relatively easy to use drop-in solution to JavaScript powered responsive images, it weighs in at about 2.4KB minified, about 1.3KB gzipped, and requires no external dependencies. Simply drop borealis on to your site and set the borealis-srcs attribute to your image and you're ready to go!

Installation

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.js or borealis.min.js to your HTML, and you're ready to rock!

Usage

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.

Browser Support

borealis uses modern JavaScript, but can supports older browsers as well. It has been tested in the following browsers but is likely to support more:

  • IE8+
  • Firefox 3.5+
  • Chrome
  • Safari
  • 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: borealis.min.js, borealis.polyfilled.min.js, and polyfills.min.js. borealis.polyfilled.min.js includes the polyfills needed to run borealis in older browsers that are missing some newer JavaScript niceties (yes, this includes IE8+) and 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

borealis has been tested in all modern browsers with thousands of images all requesting images. The limiting factor performance wise is JavaScript's native 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 min-width.

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.

tl;dr

offsetWidth and image painting are slow, requestAnimationFrame reduces layout thrashing, borealis is greedy for default then largest sizes, with great power comes great responsibility.