Implementing a modular, automated, icon system, using SVG sprites

Ed Hatrick-Smith
nib Travel Tech
Published in
6 min readAug 14, 2018

Most web UI’s use some form of icon system. Often, managing these systems can be time consuming and frustrating. An icon-font approach can result in a decent, vector solution, but they can also be slightly inconsistent and are challenging to manage.

Here at World Nomads Group we’ve implemented an approach that achieves a similar result to an icon-font and lacks many of the downsides. There are numerous, excellent, tutorials on how to implement SVG sprites with build tasks. Here we will take those learnings a step further by combining sprite build tasks with modular CSS practices. This will let us easily manage and style our icons, even and perhaps especially on large-scale web applications.

You can also skip the tutorial and look at the example project here.

Step 1: Using a task runner to create our sprite

Step 1 and 2 of this tutorial will assume that you have a basic understanding of task runners such as Grunt or Gulp. If not, you may want to up-skill on those tools first.

This project will be using Gulp, though Grunt can be used for very similar results. You will need:

  1. A set of SVG icons.
  2. A project with Gulp, using a CSS pre-processor task for bundling CSS (SASS or LESS). Here’s an example project setup for SASS.

First, we need a set of icons that have been prepared for purpose. I won’t go into too much detail around working with SVG markup, but we will need to ensure a few things:

  • Our icons need to be proportionally scaled to each other and within a matching SVGviewbox, i.e. 100 wide * 100 high. The numbers shouldn’t matter, although square is easier. Each icon does need to be the same though. This is so that we can scale and manipulate them consistently with CSS.
  • Tidy the markup of the SVG’s. SVG’s can be bloated with all sorts of unnecessary junk. Flattening, minimising paths / strokes, stripping out unnecessary tags, etc, will help prevent the sprite from ballooning in size. This can be automated via tasks such as SVGGO, otherwise it can be done manually with a little practice.
  • Within our SVG markup we need to add currentColor to a fill="" attribute on all paths where we want to control the color via CSS. This will allow the icons to inherit thecolor property of a parent element, just as you would with an icon font.

We then need to configure a task to compile the sprite. For this we will use svg-sprite. This task supports a number of sprite implementation “modes”, but in this instance we will focus on the “symbol” mode. svg-sprite will take a folder of individual icons (as SVG files), and create a single SVG with each icon in a seperate <symbol> layer. We can then reference those layers by an id="" on a <use> element, within the DOM. Example Gulp config for this:

Our symbol “mode” config with a task to compile the sprite

Step 2: Automating sprite integration with builds

In order for the SVG layers to be referenced, we need the SVG XML to be injected into our DOM. A better solution might be to reference the sprite “externally” as a static asset, which would allow for better caching, but that introduces further issues with IE as well as the need to reference the full path to the sprite in the markup.

There are numerous approaches to inline sprites into the DOM but in this instance we will use gulp-inject to take our compiled SVG sprite and inject it as XML within our template. It will take our SVG as a source, then inject that into tag’s in our page:

The Gulp “inject” task which will run the “sprite” task before injecting SVG XML

With that we need the starttag in our template for gulp-inject to insert the XML into:

Note: is-hidden state class is applying display: none; so the sprite can’t be seen in the browser.

Now, displaying an icon within the same template becomes simple with the following markup:

Referencing icon sprite layers locally with use and xlink

Now, if we want to add a new icon or change an existing icon in the sprite, we simply run the “inject” task again. At this point we can also take the “inject” task and incorporate it with the rest of our build pipeline. For example, adding it to watch and browsersync tasking for local development.

Step 3: Modularising icon styles

This step uses both modular CSS, very similar to BEM or SMACSS, as well as SCSS. Again, you may like to familiarise yourself with those first.

Typically, for brands that have well defined style-guides, icons have various restrictions on how they can be used. For instance, we might have a fixed range of icon sizes or several colour options. This restriction helps keep the UI consistent and on brand. Modular CSS helps us enforce those restrictions. Additionally, we can change icon styles globally via the CSS.

The “Icon” module with sub-modules for fixed sizes and brand colours

From here we just need to apply theIcon module class, along with any sub-module classes, to the <svg> element of each icon:

The icon set, inheriting the base font size and colour

Thanks to currentColor our icons will inherit the color from a parent. By using 1em for the width and height, they will also inherit the font-size from a parent. We would want to change those ratios if the SVG’s viewbox is not square. This is useful if we wish to use the icons within text, or to inherit the global styles for text.

Our sub-modules then become trivial to apply as needed, as we’re simply changing font-colors or sizes:

Icons with size and colour sub-modules applied

We can go one step further and create additional sub-modules with further aesthetic enhancements, such as the following Icon--circle sub-module:

The Icon — circle sub-module

The added power of this modular approach to CSS comes from the ability to mix-and match sub-module classes. Thus we can create style combinations such as:

Various sub-modules applied to individual icons

Downsides and other considerations

This approach is not perfect. You may want to consider the following:

  • Inlining the XML in the DOM isn’t ideal from a performance perspective. This is necessary at this stage thanks to IE, as per usual. It’s best to only include the icons that are actually used, to prevent bloat. Aim to keep the sprite as small as possible.
  • This approach won’t allow you to reference the icons via the content of pseudo elements. I do have a solution to this which uses the CSS sprite “mode,” but this adds quite a lot of complexity to the implementation (too much for this tutorial).
  • Some might say that referencing each icon with two HTML elements is not pretty. I agree but it’s an acceptable compromise until something better presents itself.
  • SVG 2.0 deprecates xlink in favour of simply using href.

Conclusion

We’ve come a long way from applying icons as individual images. It’s fair to say that there is still plenty of scope for icon solutions to improve. That being said, the above solution is tried and tested within contemporary commercial settings. Once it’s set up, it’s a breeze to maintain and extend. I hope you’ve found some value here.

Once again, you can download a full implementation of the project here.

--

--

Ed Hatrick-Smith
nib Travel Tech

Leader of high-performing software engineers and teams.