Using image sprites in complex projects

To complete this first chapter, I’d like to share a useful technique that can help you create and maintain an icon system based on SVG sprites.

A good icon system is one that makes it easy to find and use icons. This is why a good approach is grouping the icons in different image sprites. It’s important to keep the number of groups small (remember the HTTP requests!), but at the same time split the icons so that 1) it’s easier to know where to find an icon and 2) the size of each image sprite is low.

The two main criteria to create these groups are based on 1) size and 2) style. My favorite one is based on size (icons within the same size range often share similar styles too).

First of all, consider how many “groups” you need. Let’s say we need three groups:

1) icon-sm (small)

2) icon-md (medium)

3) icon-lg (large)

You could even be specific and use, for example, .icon-16 for 16 pixel icons, etc. It’s up to you.

In SCSS, we can define these groups like the following:

Using SCSS variables to define the sizes is optional, it can help in case of bulk changes. The reason why we use mixins for width, height and background-image is to take into account cases where we don’t want to/can’t apply the .icon class (see the example above where we use the pseudo-element).

In HTML:

<i class="icon icon--sm icon--check"></i>

SVG Symbols

I love this method because it combines the simplicity of icon fonts (copy and paste snippets to show the icons), with the power of inline SVG (edit colors, stroke values, etc.). The SVG symbol is, in a way, an SVG sprite: an SVG file containing all icons. In this case, though, the icons are not arranged in a grid; the position of the icons does not matter.

This technique is based on the use of two elements: <symbol> and <use>.

The <symbol> element is used to group elements together; it is never displayed, but it instead defines a template which can be rendered using a <use> element.

How SVG symbols work

Let’s consider the code of an SVG icon:

<svg width="48" height="48" viewBox="0 0 48 48">

<title>skull</title>

<path d=".." fill="none" stroke="#444" stroke-width="2"/>

</svg>

We know that if we paste this code into our document, the icon is visible. However, if we wrap the content of the icon inside a <symbol> element

<svg style="display: none;">

<symbol viewBox="0 0 48 48" id="skull">

<title>skull</title>

<path d=".." fill="none" stroke="#444" stroke-width="2"/>

</symbol>

</svg>

and we insert this code into our document, the icon is no longer visible; that’s because we need to reference it using the <use> element. Somewhere else in our document (where we want to place the icon), we need to use the following snippet:

<body>

<svg><use href="#skull" xlink:href="#skull"/></svg>

</body>

(Note that even though xlink:href has been deprecated, the href attributed inside an SVG element is not supported in Safari 11. Once the SVG 2 specification is supported by all browsers, you can safely remove xlink:href.)

To recap: once you have grouped each icon (using the <symbol>), you can display it as many times as you want using the <use> element. To specify which icon you want to display, use the href attribute, whose value is the ID of the <symbol> element.

You may have noticed that we added a style=”display: none;” to the SVG wrapping the <symbol> element: even if the <symbol> is not displayed, the <svg> element wrapping it is still rendered and will take up some space in our page, and this is why we need to hide it.

How to generate SVG symbols

To create the SVG file that contains all your icons, group each icon into a <symbol> element.



<symbol viewBox="0 0 48 48" id="skull">

<title>skull</title>

<path d=".." fill="none" stroke="#444" stroke-width="2"/>

</symbol>

<symbol viewBox="0 0 32 32" id="check">

<title>check</title>

<path d=".." fill="none" stroke="#444" stroke-width="2"/>

</symbol>

<symbol viewBox="0 0 48 48" id="home">

<title>home</title>

<path d=".." fill="none" stroke="#444" stroke-width="2"/>

</symbol>

</svg> http://www.w3.org/2000/svg " style="display: none;"> skull check home

Each <symbol> element needs to have an ID; this ID will be used to reference it inside your document using <use>.

Note that we have specified a viewBox attribute for each <symbol> element. The viewBox attribute defines the aspect ratio of your icon. It is composed of 4 numbers, the first 2 are usually zero (but it really depends on how the icon was drawn), while the other 2 are the width and height of the icon. If you’re not familiar with the viewBox attribute, you should take a look at this article about scaling SVG.

Your icons do not need to have the same size since you can define a different viewBox attribute for each one of them.

Finally, it’s good practice to add a <title> tag in each SVG icon to improve accessibility.

Now that our SVG file is ready, where do we store it? Option 1 would be including the SVG code at the top of the document, right after the <body> element. Ideally, you can create a component, or a partial, to store the icons:

<!doctype html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="assets/css/style.css">

<title>Title</title>

</head>

<body>

{% include "_icons.nunjucks" %}

Once again, to display one of your icons you need to insert the following snippet somewhere in your document:

<svg><use href="#skull" xlink:href="#skull"/></svg>

This method is supported by all modern browsers (IE9+).

Option 2 would be storing the icons.svg file (containing all your icons) in your assets folder. This is referred to as “using an external reference”. If you do so, the snippet used in your document changes a bit:

<svg><use href="assets/icons.svg#skull" xlink:href="assets/icons.svg#skull"/></svg>

The value of the href attribute needs to include also the external reference.

This method is not supported by Internet Explorer (I know, right?). However, you can use a polyfill like svgxuse to fix the issue with the old IE friend.

Creating and maintaining SVG symbols can be a lot of work. Luckily, tools like Nucleo can generate and update these files in no time!