Sprites without JS or min-device-pixel-ratio

(05-24-2014).

This post is about serving a Scalable Vector Graphics (SVG) file in lieu of a “high-resolution” image (@2x). It is an alternative to this:

/* MQ syntax from http://benfrain.com/how-to-serve-high-resolution-website-images-for-retina-displays-new-ipadiphone4/ */
@media (min-resolution: 192dpi), (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2/1), (min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
    .sprite {
        background-image: url('/img/sprite@2x.png');
        background-size: 400px 100px;
    }
}

Or this (which relies on JavaScript):

.sprite {
    background-image: url(sprite@2x.png);
}
.no-svg .sprite {
    background-image: url(sprite.png);
}

Stop the presses! Check the update section

pixel-ratio agnostic

If we check caniuse.com for Scalable Vector Graphics (SVG) and Media Queries (MQ) support, we can see that those charts look pretty much the same.

For SVG as backgrounds, partial support refers to scaled images, tiling, and the background-position property.

Sprites in general do not need to tile. SVG sprites do not need to be resized while PNG sprites do (for high-definition displays). Unless you have to support iOS versions prior to 4.2 or Android 2.x, a SVG sprite should be safe.

The idea is to serve the SVG file depending on MQ support rather than targeting pixel ratios. We can do this with a simple:

@media {
    .sprite {
        background-image: url(sprite.svg);
    }
}

Yes, @media { … } is legit. It is the same as @media all { … }

Fallback

For Internet Explorer 6, 7, and 8, we serve a PNG - of the same size - via these rules:

/* IE 6 and 7*/
.sprite {
    *background-image: url(sprite.png);
}
/* IE 8 */
@media \0screen {
    .sprite {
        background-image: url(sprite.png);
    }
}

If the above is too ugly for you, or if you want to make sure your style sheet validates, then you can hide all that in a conditional comment:

<!--[if lt IE 9]>
    <link rel="stylesheet" href="ie678style.css">
<![endif]-->

Update

SelenIT suggested in the comments that we can use the same “feature support” logic to serve each file to the right browsers, but this time relying on support for “multiple backgrounds”, like this:

.sprite {
    background-image: url(sprite.png); /* old browsers (ie6/7/8) */
    background-image: none, url(sprite.svg);  /* modern browsers */
}

Thanks to SelenIT for suggesting this very elegant solution. But remember that Android 2.x does not support SVG as background images.

Wrap up

In my opinion, this approach has a few advantages: