How to Use SVG Image Sprites

Craig Buckler
Craig Buckler
Share

This tutorial describes two ways to create sprites containing many images. However, it uses SVG rather than the more well-known bitmap techniques.

SVGs are ideal for logos, diagrams, and icons for several reasons:

  • It’s easy to created and manipulate SVGs on the client or server.
  • Unlike bitmaps, SVGs can be scaled to any size without losing quality.
  • Unlike webfont icons, SVGs remain pin-sharp and can apply multiple colors, gradients, and even complex filters.

What are 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. For example:

image sprite

This example contains eight 24×24 icons in a single 192px × 24px file. The file may offer slightly better compression and it only requires a single HTTP request for all icons to become visible. Loading eight separate icons is unlikely to take much longer over HTTP/2, but the images could appear at different times and would only be cached on first use.

If you wanted to show the right-most printer icon, CSS can display the correct image by positioning the background:

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

Various tools can be used to calculate pixel positions and generate CSS code:

SVG Image Sprites

Multiple SVG images can also be placed into a single SVG file and each can be referenced by an ID rather than a pixel position.

The most common technique is to define individual images within an SVG <symbol>. For example, this SVG contains a green circle, red square, and blue triangle:

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

  <symbol id="circle">
    <circle cx="50" cy="50" r="45" stroke-width="5" stroke="#0f0" fill="#0f0" fill-opacity="0.5" />
  </symbol>

  <symbol id="square">
    <rect y="5" x="5" width="90" height="90" stroke-width="5" stroke="#f00" fill="#f00" fill-opacity="0.5" />
  </symbol>

  <symbol id="triangle">
    <path d="M20,7 L92,50 L6,93 z" stroke-width="5" stroke="#00f" fill="#00f" fill-opacity="0.5" />
  </symbol>

</svg>

A single sprite can be used any number of times throughout a page with SVG <use>:

<svg width="100" height="100">
  <use xlink:href="./spriteuse.svg#circle" />
</svg>

<svg width="100" height="100">
  <use xlink:href="./spriteuse.svg#square" />
</svg>

<svg width="100" height="100">
  <use xlink:href="./spriteuse.svg#triangle" />
</svg>

Unfortunately, older browsers such as IE11 and below won’t load the external image. The best workaround is to embed the full SVG into the HTML markup and reference each sprite using its target. For example:

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

  <symbol id="circle">
    <circle cx="50" cy="50" r="45" stroke-width="5" stroke="#0f0" fill="#0f0" fill-opacity="0.5" />
  </symbol>

  <!-- further images -->

</svg>

<!-- display circle -->
<svg width="100" height="100">
  <use xlink:href="#circle" />
</svg>

SVG Sprite Stacks

The <use> element is a little long-winded and can only be used within an <svg> (either a standalone image or embedded within HTML). It can’t be used in an <img>, <iframe>, <object>, or as a CSS background.

The SVG stacks technique first documented by @simurai and @erikdahlstrom in 2012 provides one way around this restriction. Individual sprites are assigned a class of "sprite" and embedded CSS sets them to display:none by default. However, display:inline is applied when a sprite is the target element:

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

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

  <g class="sprite" id="circle">
    <circle cx="50" cy="50" r="45" stroke-width="5" stroke="#0f0" fill="#0f0" fill-opacity="0.5" />
  </g>

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

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

</svg>

If this SVG is named sprite.svg, you can add a #target-name to the URL to show a specific sprite. For example, the URL sprite.svg#circle displays the layer with the ID of "circle" at any dimensions you choose. It can therefore be used in an <img>:

<img src="./sprite.svg#circle" width="100" height="100" />

Or as a CSS background:

.myelement {
  background: url('./sprite.svg#circle');
}

Or in an <iframe>:

<iframe src="./sprite.svg#circle">
  Your browser does not support iframes.
</iframe>

Or in an <object> tag:

<object type="image/svg+xml" data="./sprite.svg#circle">
  <img src="./fallback-image.png" />
</object>

The method works in all browsers including Internet Explorer 9 and above.

SVG stacks are less popular today, because embedding SVGs directly into the HTML has become a best-practice technique. However, it could be ideal when you require lots of SVG icons and don’t need to manipulate them directly using CSS or JavaScript.

Frequently Asked Questions (FAQs) about SVG Image Sprites

What are the advantages of using SVG image sprites over traditional image sprites?

SVG image sprites offer several advantages over traditional image sprites. Firstly, they are resolution-independent, meaning they can scale to any size without losing quality. This makes them ideal for responsive web design. Secondly, they have smaller file sizes compared to raster images, which can improve website loading times. Lastly, SVGs can be styled and animated with CSS and JavaScript, providing more flexibility and interactivity.

How can I create an SVG sprite?

Creating an SVG sprite involves combining multiple SVG images into a single file. This can be done manually using a text editor or with the help of tools like Grunt, Gulp, or webpack. Once combined, each SVG image is assigned a unique ID that can be used to reference it in your HTML or CSS.

How do I use an SVG sprite in my HTML?

To use an SVG sprite in your HTML, you reference the sprite file and the ID of the specific SVG image you want to use. This is done using the ‘use’ element and the ‘xlink:href’ attribute. For example: <svg><use xlink:href="sprite.svg#icon-id"></use></svg>. Replace ‘icon-id’ with the ID of your SVG image.

Can I style SVG sprites with CSS?

Yes, SVG sprites can be styled with CSS. You can apply styles to the ‘svg’ and ‘use’ elements in your HTML. However, keep in mind that some CSS properties may not work as expected due to the nature of SVGs.

Are there any limitations or drawbacks to using SVG sprites?

While SVG sprites offer many benefits, they also have some limitations. For example, they may not be fully supported in older browsers. Additionally, complex SVGs can have larger file sizes and may require more processing power to render.

Can I animate SVG sprites?

Yes, SVG sprites can be animated using CSS or JavaScript. This allows for a wide range of effects, from simple transitions to complex animations.

How can I optimize my SVG sprites for better performance?

There are several ways to optimize SVG sprites for better performance. These include minifying the SVG code, removing unnecessary metadata, and using gzip compression. Tools like SVGO can help with this process.

Can I use SVG sprites for background images?

Yes, SVG sprites can be used for background images in CSS. However, this requires a different approach than using them in HTML. You would need to use the ‘background-image’ property and reference the sprite and icon ID in the URL.

How can I make my SVG sprites accessible?

To make SVG sprites accessible, you can use ARIA attributes and provide alternative text for screen readers. This can be done using the ‘aria-hidden’ and ‘aria-labelledby’ attributes, and the ‘title’ and ‘desc’ elements in your SVG code.

Can I use SVG sprites in responsive web design?

Yes, SVG sprites are ideal for responsive web design due to their scalability. You can control their size using CSS, and they will always render crisply at any resolution.