Easily create image sprites for retina displays

With the launch of the new iPad all websites instantly became pixelated and ugly. All your neat images and sprites and stuff is now rubbish. You’ll need to remake it all. In twice the width and height.

This post has been updated for your pleasure

Because this post seem to be quite popular I decided to update it a bit with cleaner and much better code and even a demo!

A Retina Sprite Grid in Photoshop

When it comes to graphic and icon design it can sometimes feel like a part-time job just to keep them updated and you easily end up with billions of files scattered around in silly folders. Add retina to that, and you’ll double that number.

A retina display has twice the pixels as a normal display but at the same resolution. That means that all fixed size graphics needs to be doubled in width and height in order to keep the sharpness of the graphic.

However, using the old school method of sprites it can simplify things quite a bit. It can even help solving the retina display issue without any need of JavaScript.

Making your sprite retina proof

The first very important thing is that the retina sprite must be exactly twice as wide and twice as high as the normal sprites in order for this to work properly. In my example I use a sprite with the size of 200px x 200px. In order for this to work my retina sprite must be 400px x 400px.

This example simply list 4 different icons. A cross, a star, a hamburger menu and a plus sign.

<div class="iconlist">
  <ul>
    <li class="sprite white-cross"></li>
    <li class="sprite filled-star"></li>
    <li class="sprite white-menu"></li>
    <li class="sprite white-plus"></li>
  </ul>
</div>

We add some CSS to the demo as well and create a class where we set the normal sprite image as background-image.

Now, this is important, so pay attention. The background-size must have the same value as the width of the normal sprite. In this case 200px.

    div.iconlist {
      padding: 40px;
      background-color: #448ccb;
    }

    .sprite {
      background-image: url(img/iconsprites.png);
      background-repeat: no-repeat;
      background-size: 200px;
    }
    li {
      list-style: none;
      padding: 0;
      margin: 0;
      margin-right: 20px;
      width: 50px;
      height: 50px;
      display: inline-block;
    }

Next, we need to position the background image for each of the icons. This can sometimes be quite tedious work, but I always divide my sprites into a 50x50px grid and position the icons in that grid. So I know that a new icon begins every 50px. Saves a lot of hassle!

    li.white-cross {
      background-position: -50px -50px;
    }
    li.filled-star {
      background-position: -50px 0px;
    }
    li.white-menu {
      background-position: -100px 0px;
    }
    li.white-plus {
      background-position: 0px -50px;
    }

Now, that’s all very easy and utterly useless you might think. But I’m not done yet. In order to get all this to render beautifully on a retina display we only need a few lines of CSS. Really.

We add a media query to target only screens with retina displays and we change the sprite used for background-image to our retina sprite.

@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (min--moz-device-pixel-ratio: 1.5),
only screen and (min-resolution: 240dpi) {
.sprite {
    background-image: url(img/iconsprites@2x.png);
  }
}

Voila! You’re done!

Now it’s retina proofed! Notice that you didn’t need to do much coding at all? No magic JavaScript or anything?

You can try out my demo on Codepen and see for yourself and steal the code if you like.

Last notes about sprites and grids

I use this little script for Photoshop to create this nice 50x50px grid for all my sprites. It’s made by Filip Van Tendeloo.

Thoughts and comments

  1. I’ve been trying to find out, perhaps you know: with this approach, do HDPI devices download both the 1X and 2X images or are browsers smart enough to only download the 2X?

    1. I’m afraid the device will download both. You’ll need a server side request handler to decide what stuff to download depending on user device.

      Some CMS like Episerver CMS 7 the CMS handles that. WordPress doesn’t do that. Yet.

      1. This is incorrect. Only when the style is applied the image is loaded. So if the retina media query does trigger and overrides a default image, the default image will not be downloaded.

        1. It is not.

          If you open Google Chrome developer tools and check the network tab and reload, you can see that the website loads both image files.

          As all CSS parsers aren’t aware of what will happen next, all images referenced will be downloaded, even if the very next section will overwrite that command.

          1. Hello there

            Thanks for a fantastic article – this was a lot of help!!

            I have tested my site in Google Chrome (v32) using the developer tools and found that it doesn’t load both versions of the sprite atlases. The “Network” tab only shows one of them actually being loaded.

            Perhaps Google have optimised the way in which they load resources when media queries are in use…

            Anyhow, thanks again!!

  2. I suppose you also have to add a “display:none” to ul.retina on non-retina displays and then change it to “display:block” on retina displays.

    ul.retina {
    display:none;
    }

    and then with media queries:

    ul.retina {
    display:block;
    }

  3. It’s better to put background-size property inside “retina media query” block. Because we need to set background-size only for retina spritesheet.

  4. Seems like a lot of manual work still. I’d recommend exporting the icons individually in their 2x size and then bring them into a free online sprite generator to put it all together in an optimized fashion. That way you can easily add a new sprite, and re-export and replace it on your site in a matter of minutes. No need to wrangle a photoshop file—which just gets difficult overtime. I might be partial but I recommend this sprite generator if you need retina support, a CSS embedded sprite and/or JSON output: https://www.facetstudios.com/sprite-generator

Share your thoughts on this

Your email address will not be published.