connect-assets + node-sprite for effortless retina compatible CSS sprites

EDIT: I normally now prefer to just use SVG for as much as everything, but in case this is not possible sprite maps might still be a good choice.

I have to admit I was a bit late to the CSS sprite game, but I'm definitely hooked by the advantages:

  • Faster page loads: only one image to download for all your site-wide graphical assets
  • No need for image pre-load hacks: since all of your generic images assets are downloaded in one go, all your rollovers will perform great

The big drawback is just that if you want to manage your CSS sprites manually, it will be a bloody headache. Luckily thanks to the wonders of open
source software, there already exists a plethora of great libraries out there to help you manage your CSS sprites. For Node.js I found a great little
library node-sprite which together with Stylus and connect-assets makes managing retina sprites a piece of piss.

Integrating with connect-assets and Express

Integrating node-sprite together with connect-assets was a bit of a pain however, so I thought I'd walk through how I set things up in my project.
Check my blog post on setting up connect-assets if you want to
find out how to set that up, I'm building on a similar setup to the one described there.

First install node-sprite:

npm install node-sprite

Now we want to register a couple of stylus helpers that node-sprite exposes with connect-assets like this in our Express setup (I'm using Zappa here):

# Load the node-sprite library
sprite = require('node-sprite')

# Setup node-sprite sytulus helper, which reads the sprites from /public/sprite
nodeSpriteStylusHelper = sprite.stylus {path: "./public/sprite", httpPath: "/sprite" }
nodeSpriteExtension = (style) ->
   style.define('sprite', nodeSpriteStylusHelper.fn)
   style.define('sprite-dimensions', nodeSpriteStylusHelper.dimensionsFn)

 # Configure connect-assets with our node-sprite extension
 connectAssets = require('connect-assets')
 @use connectAssets({
     buildDir: "public"
     pathsOnly: true,
     stylusExtends: nodeSpriteExtension

So now the sprite and sprite-dimensions functions are available to any of our stylesheets which is nice.

Making our first sprite

If i want to make a CSS sprite called 'icons' with retina support, I need to create two folders with my icons like so:


So I have normal icons in the 'icons' folder and my retina icons (with twice the pixel size) in my icons-2x folder. Now if I want to display this
icon in my page I can have simple markup like this:

<div id="monkey"></div>

And in my stylesheeet:

@import 'mixins'

// This will generate all the css for showing our monkey both on normal and retina screens, goodness!
    retina-sprites icons monkey

In the 'mixins' import this mixin that i took from the node-sprite documentation handles generating the CSS:

retina-sprite(folder, name)
  sprite(folder, name)
  hidpi = s("(min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx)");
  @media hidpi
    sprite(folder+"-2x", name, false)
    background-size sprite-dimensions(folder+"-2x", name)

This uses the sprite and sprite-dimensions functions we extended Stylus with.

You're done

So now to add more retina compatible icons we just need to drop images into our sprite directories and add a couple lines of to our stylesheets, and
we're done!