Get my newsletter
About once a month, I publish an article on something I've learned in the creative industry.

A stab at a retina sprite workflow

I'll assume you're on board with the idea of using CSS sprites and that they just make sense. So let's kick things off by making a sprite file. I’m using Illustrator in this example but the same ideas apply whatever you’re using, so go nuts.

You'll want to begin by making a canvas for all your sprites to sit on. Choose a sensible size which will allow you to add a few sprites as the project grows (you can always resize it later anyway). I’ve gone for 500px by 200px here.

Sprite file in illustrator

It's worth saying that you should add new sprites to the spritesheet from the top left out, leaving existing sprites where they are. This way the position of original sprites will always be the same in your CSS.

Once you’ve added your sprites to your spritesheet, the next step is to save the file out as a transparent PNG in two sizes:

  1. A standard spritesheet, named [email protected]
  2. A retina spritesheet, exactly twice the size of the standard spritesheet, named [email protected].

Our sprites are now ready to use. Lovely. Time to write some code. Let's create a Sass placeholder rule called %sprite, with the basic CSS rules we want all sprites to have:

%sprite {
  display: inline-block;
  // We're referencing the retina sprite here ([email protected])
  background-image: url('/path/to/[email protected]'); 
  // ...but using the dimensions from 
  // the standard sprite ([email protected])
  background-size: 500px 200px; 
  background-repeat: no-repeat;
}

The important thing to note here is that we're effectively scaling the retina sprite to half it's natural size. This means we can use it on standard screens with no problem but still have a sharp image on retina screens. At this point you could also add a media query to only use the retina sprite on retina screens, and serve the standard sprite as default. This will save bandwidth when the retina sprite isn’t necessary.

%sprite {
  display: inline-block;
  background-image: url('/path/to/[email protected]'); 
  background-size: 500px 200px; 
  background-repeat: no-repeat;

  @media (-webkit-min-device-pixel-ratio: 2), 
    (min-resolution: 192dpi) { 
    // only show retina sprite where needed
    background-image: url('/path/to/[email protected]'); 
  }
}

Next, point yourself over to Sprite Cow and upload the [email protected] (standard) spritesheet. This web-based sprite tool lets you 'lasso' your sprites and get pixel values for their position. As an alternative to the nudge-css-values-in-dev-tools approach, you can't beat it.

Spritecow in action

This is where the magic of having a 1x and 2x spritesheet comes into play. We now know the position of the triangle sprite on the 1x spritesheet, but because the retina spritesheet it exactly double the size and is being scaled down, the same measurements apply.

So, we can now take the measurements Sprite Cow gave us and create a new .sprite--triangle class:

// Base sprite styling
%sprite {
  display: inline-block;
  background-image: url('/path/to/[email protected]'); 
  background-size: 500px 200px; 
  background-repeat: no-repeat;

  @media (-webkit-min-device-pixel-ratio: 2), 
    (min-resolution: 192dpi) { 
    background-image: url('/path/to/[email protected]'); 
  }
}

// Triangle sprite
.sprite--triangle {
  // Extend the base sprite style above
  @extend %sprite; 
  // Apply custom position specific to the triangle
  background-position: -120px -9px;
  width: 43px;
  height: 43px;
}

You can now let the .sprite--triangle class run riot over your HTML, safe in the knowledge it will be serving standard sprites where you need it to, and retina where appropriate. The process for adding new sprites from here is simple:

  1. Add the new sprite to your source file and save out at 1x and 2x size
  2. Upload to Sprite Cow and get the sprite dimensions/positions
  3. Create a class for the sprite in CSS in the same format as .sprite--triangle

Another plus is that if you need to resize the spritesheet, either to add more sprites or to remove blank space, you only need change the background-size attribute on the %sprite placeholder class.

And there you have it. It's not glamorous, but having a workflow in place for dealing with retina sprites has certainly made working with various resolutions less painful.

Posted September 2014
© 2014-2018 James Chambers
Learn from my mistakes
x

Sign up to my mailing list to get insights about starting, running and growing a creative company.