How to Use SVG Image Sprites

Tweet

Despite being scalable, saving bandwidth and an obvious candidate for Responsive Web Design, Scalable Vector Graphics (SVGs) are relatively rare on the web. The reasons?

  • SVGs don’t work in older versions of Internet Explorer — support is only available in IE9+
  • the technology has been around since 1999 — it seems old and unexciting
  • there are fewer vector design tools
  • they’re XML-based which sounds scary to many.

Let’s show some love for SVGs! SVGs are ideal for logos, diagrams and icons. Unlike bitmaps, SVGs can be scaled to any size without losing quality and manipulated using client-side and server-side code. Unlike webfont icons, SVGs can have multiple colors, gradients and even complex filters.

Bitmap Image Sprites

Image sprites have been a good-practice technique for many years. If you require a number of regularly-used graphics, you place them in a single image rather than individual files, e.g.

image sprite

This example contains eight 24×24 icons in a single 192×24 file. The file may offer slightly better compression but the main advantage is it only requires a single HTTP request for all icons to become visible. Loading eight separate icons would take longer since there is more data to download and browsers have a limited number of concurrent requests per domain.

If we require the right-most printer icon, we can use CSS to show the correct image by positioning the background:

#print
{
	width: 24px;
	height: 24px;
	background: url("sprite.png") -168px 0;
}

SVG Image Sprites

Is it possible to place multiple SVG images in one file? Absolutely! They also have an advantage over bitmap sprites; you can refer to each image by name rather than calculating pixel positions. As far as I’m aware, this SVG stacks technique was devised by @simurai and @erikdahlstrom although others may have contributed.

We’ll create a very simple SVG with three individual icons — a green circle, red square and blue triangle:

<?xml version="1.0"?>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">

<g class="sprite" id="circle">
	<ellipse cy="50" cx="50" ry="45" rx="45" stroke-width="5" stroke="#00ff00" fill="#00ff00" fill-opacity="0.75" />
</g>

<g class="sprite" id="square">
	<rect y="5" x="5" width="90" height="90" stroke-width="5" stroke="#ff0000" fill="#ff0000" fill-opacity="0.75" />
</g>

<g class="sprite" id="triangle">
	<path d="M20,7 L92,50 L6,93 z" stroke-width="5" stroke="#0000ff" fill="#0000ff" fill-opacity="0.75" />
</g>

</svg>

Each is stacked on top of the other in a separate g layer which has a class of “sprite” and a unique ID. View the image and you’ll see all three:

SVG

Here comes the clever part — you can add a couple of CSS rules to the SVG file which hide all layers except for active layer determined using the :target pseudo selector:

<defs>
	<style><![CDATA[
		.sprite { display: none; }
		.sprite:target { display: inline; }
	]]></style>
</defs>

Therefore, if our file is named sprite.xml, we can add a #hash-name to the URL show a specific image, i.e. the URL sprite.xml#circle will display the layer with the ID “circle” at any dimensions you choose.

View the SVG sprite demonstration page…

There are a number of methods you can use to add SVG sprites to your page: object/embed, an iframe, an img tag or a CSS background. The demonstration shows all techniques and they work well in Internet Explorer 9+, Firefox and Opera 12 and below.

Unfortunately, the img and CSS background methods fail in the Webkit/Blink browsers — Chrome, Safari and Opera 15+. There are various on-going discussions but there is no guarantee SVG stacks will ever be fully supported. That’s a shame because the technique seems so useful.

Unless Webkit can be persuaded to join the SVG stacks party, object or embed is the best cross-browser solution, e.g.

<object type="image/svg+xml" width="100" height="100" data="sprite.svg#circle"></object>

This also has the advantage that you can directly address and update the SVG sprite using DOM scripting.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Steven Richardson

    Great article Craig. I love SVG’s and the quality it brings your site when in use however there is a major drawback to using SVG’s in sprites, retina displays. I have tested on several retina devices including iPad 3, iPhone 5 and iPhone 4S and found that when zooming into a page on one of these devices while using sprites would always crash the browser, removing the sprites solved the issue leaving me to believe the cost of redraws on the zoom for hi res displays was too great for the browsers to handle. Would love to hear anyone else’s findings on this. I wrote about it here http://www.richdynamix.com/blog/web-development/svg-vs-png-in-sprites-an-ios-issue

    Steven

  • Jeroen Oliemans

    Good stuff, you could also use the viewbox attribute values to mask more complex image sprites for example created in Illustrator. You would need to include the sprite SVG for each icon / graphic though

  • Anonymous

    Lovely technique! If only we could reference the sprite once though. With a complex image sprite you could end up having a huge page weight.

    I’ve run into the same issue as Steven Richardson, which seem like the best solution, but not if you want your site to work on iOS devices…

    Think the best way still to get these results is to add the SVG in your CSS with a background-image and as a data URI. Looking forward to the day a better and stable solution is available!

  • Pablinho

    Which browsers is this supposed to work on ?
    Tried the demo ( using chrome’s latest version ) and the last 2 items, img and css bgs dont show up at all.