CSS Retina Sprites

This topic can be easily avoided by using SVG instead of sprites, since SVG icons will always appear crisp and non-pixelated. However, if we have to support browsers such as IE8 and older, using SVG isn’t reasonable without using things like polyfills. That’s where sprites can come in handy.

CSS sprites are great for things like icons and small images. They reduce the overall number of HTTP requests rather than calling each image individually and therefore (in most cases) provide a performance boost. This is especially important in cases such as mobile use or slow Internet connections where every bit of data is precious.

If you’re just learning about Sprites, you might want to check out other resources such as Chris Coyier’s post: “CSS Sprites: What They Are, Why They’re Cool, and How To Use Them.“.

Retina screens add a new wrinkle to Sprites because generally icons and small images are what look worst on high pixel density devices.

Maykel Loomans wrote a great article on using CSS Sprites with Retina that boils down to:

  1. Make retina sprite at exactly twice the size of the normal sprite.
  2. Change out the background-image with a media query.
  3. Set the background-size to 50% of the full width.

Simple enough. But when I went to implement his suggestions, the sizes of all of the icons were totally off. Off by exactly 50%, to be specific.

Turns out I was using background-size: 50%; instead of the required background-size: {1/2 total sprite width}px;. If we look at the CSS spec for background-size on the MDN,

A value that scales the background image in the corresponding dimension to the specified percentage of the background positioning area, which is determined by the value of background-origin. The background positioning area is, by default, the area containing the content of the box and its padding;

Essentially what that boils down to is that if you use a percentage with background-size, it is a percentage of the elements width or height. So if you have a sprite with a normal width of 200px, a retina width of 400px and CSS something like the following:

.logo {
    width:50px;
    height:50px;
    background-image: url('some_logo.png');
    background-position: 0 0;
}
@media(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
    .logo {
        background-image: url('some_logo@2x.png');
        background-size:50%;
    }
}

The size of the image from the sprite will be 25px on retina screens. This is because it’s looking at the containing element, and setting the background-size to 50% of it’s width. To fix this, change background-size:50%; to background-size:200px;

That tells the browser to show the background size at 200px instead of it’s natural 400px, thereby shrinking the sprite to exactly 50% of the size of it’s parent.

I might have been the only one confused about the way background-size works, but it was definitely good to learn!

Leave a Reply

Your email address will not be published.