Scaling images for Retina displays

There are several off-the-shelf solutions for providing super-sized images to devices using Apple’s retina display. One good choice is retina.js–a nifty little plugin for swapping in double-pixel images whenever a retina display is detected. It performs cool tricks like testing to ensure that retina images are actually available, and provides a LESS rule for automagically using a media query to scale background images when they are. That saves a bit of code (if you’re using LESS), but the introduction of a second detection strategy means an extra point of failure to test and maintain.

Instead, we can use a class (think Modernizr’s highres) to keep all brittle detection in once place. For everyone else, read on.

  1. Detect retina with javascript
  2. Swap any low-res images for their high-res equivalents
  3. Add a “retina” class to the body element
  4. Update stylesheet to serve retina images within .body

The substitution of a class for retina.js’s media query trades a little more work on individual styles for the isolation of device-detection code. The resulting implementation will still support both HTML <img> elements and CSS background styles–it just goes about it in a slightly different fasion.

For the sake of brevity, let’s (naively) assume that 2x versions exist for all images. This allows us to forego testing their existence, and produces a script that looks something like this:

445 uglified bytes later, we’re well on our way to supporting Retina devices. Note that all of the device detection is contained in a single function:

var isRetina = function () {
    return window.devicePixelRatio > 1;
};

If we ever decide to add more sophisticated tests, updating isRetina will carry throughout our site. The only step remaining is to update elements with background images to use their 2x versions if a retina display is detected. It probably looks something like this:

/** in stylesheet.css **/
.div-with-bg {
    background-image: url(/path-to-image.jpg);
}

.retina .div-with-bg {
    background-image: url(/path-to-image2x.jpg);
    background-scale: contain; /* scaling strategies may vary */
}

Now, if the .retina class is attached to the body, any elements with the div-with-bg class will use the larger version when viewed on a retina display.

There’s a fiddle demonstrating the completed script here.

Featured