A basic implementation of SVG sprites

As devices with high definition displays have become the norm the Money Advice Service development team has had to consider moving away from bitmap image formats to more flexible vector-based formats, such as scaleable vector graphics (SVG). However, the MAS website is required to support Internet Explorer 8 as part of our organisation’s browser matrix, and consequently as IE 8 does not support SVG we have relied on using PNG image files for iconography and other decorative images.

This was the approach that the frontend team took when we built the new responsive public website in 2014. Specifically, and in order to address the rise of high definition “retina” screens, we used double-sized PNG files and scaled them down to achieve sharp images on Apple’s newest devices. The drawback of this technique was that the browser would load a file that was often over double the weight on devices not capable of displaying the high definition images. Furthermore it involved complex media queries to control the scale of the image on different devices. Now with Apple, amongst others, starting to sell devices with screen resolutions up to 5k providing double-sized PNG files becomes untenable. Therefore going forward we have decided to take an aggressive stance on applying SVG to our products.

Starting with projects such as the Your Money Advice blog and the Retirement Adviser Directory (currently being built) we are aggressively using SVG iconography and images where the images are decorative. This means that if a user loads the website on Internet Explorer 8 and the image is not displayed then there is not loss of functionality for the user. An example of this could be a menu button that uses only a burger icon, and a pagination button that uses the words “next page” along with an arrow icon. The burger icon stands on its own, and if it fails to load renders the menu unusable. However, if the arrow in the pagination button fails to load then the button text still communicates the function to the user.

Having decided to make the move to SVG we considered whether we would load the images as background images, include them in the page “inline” with the markup or reference them in an <img src="" /> tag. We decided to inline them and include the icons collated in a markup-based SVG image sprite. This way the sprite would be loaded when the page loads, and cached. Furthermore as the <svg> would be inline the individual parts of the SVG tag, the <path> and <circle> tags, for example, could have classes applied to them. Attaching classes to the constituent parts of the SVG allows us to control the properties of the image through CSS. The most obvious, and useful, reason for doing this is to control the colour of the image if it appears in different page components.

The Money Advice Service website is a Ruby on Rails application. Therefore we make extensive use on the ERB template language to render HTML partials. The sprite is saved in the file _svg_icons.html.erb is which lives in the app/assets/images directory:

<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="icon-pagination-next" viewBox="680.1 0 161.8 278.5" enable-background="new 680.1 0 161.8 278.5">
    <path fill="#010202" d="M702.1 278.5l-22-22 117.3-117.3L680.1 22l22-22 139.8 139.8-139.8 138.7z"/>
  </symbol>

  <symbol id="icon-pagination-prev" viewBox="-12 232 161.8 278.5" enable-background="new -12 232 161.8 278.5">
    <path fill="#010202" d="M127.8 232l22 22L32.5 371.3l117.3 117.3-22 22L-12 370.7 127.8 232z"/>
  </symbol>

  <symbol id="icon-back-to-top" viewBox="0 0 512 512">
    <path d="M256 89.873l-76.256 76.255L0 345.872l76.255 76.255L256 242.384l179.745 179.744L512 345.874 332.256 166.128 256 89.873z"/>
  </symbol>
</svg>

Then the sprite is rendered into the main layout application.html.erb, above any required script tags (such as the tag that kicks RequireJS into gear) as follows:

<%= render '../assets/images/svg_icons' %>

Once the SVG sprite is rendered into the page then the individual <symbol> can be referenced from within any other HTML document, or partial as follows:

<svg xmlns="http://www.w3.org/2000/svg" class="back-to-top__icon">
    <use xlink:href="#icon-back-to-top"></use>
</svg>  

The <use> tag directly references the id of the <symbol> and pulls the contents into the surrounding <svg> tag to render it on the page.

This gives us several distinct advantages. First, as discussed above we can assign a class to the images constituent parts and change its properties. Secondly, all of the SVG images can be contained within one HTML partial which eases maintenance. Compared to a static PNG sprite, which would have to be amended in Photoshop every time an icon is added or removed, this is much easier.

Optimising the SVG with SVGO

After acquiring the vector images from our designer we use SVGO, a Node based optimiser for vector graphics to strip out all of the unnecessary elements of an SVG file, and to minify the file removing the whitespace and the line breaks. SVGO removes various unnecessary parts of an SVG file, namely:

  1. the doctype declaration;
  2. the version number (ignored by all user agents);
  3. comments that annotate the file;
  4. and of course, newlines, trailing and repeating spaces.

It removes many other artefacts however for those familiar with the SVG files produced by Adobe Illustrator the above is what will be visually stripped out.

Sidenote: SVG namespacing

SVG is an XML dialect, and as such needs to be namespaced. In a nutshell this means that different types of XML (e.g. vector graphics and MathML) can live together in the same document. However, to exist in the same page they must be ‘namespaced’ and that is accomplished by adding the xmlns="" attribute to the XML tag, like this:

<svg xmlns="http://www.w3.org/2000/svg">  
    <!-- tags that could be similar to those found in other XML dialects -->
</svg>

Therefore this attribute should not be removed during optimisation.

What about PNG fallbacks

So the question still hovers ominously in the air. What about a PNG fallback solution, even if it is only for IE8. Additionally if we want to roll this out to logos and other context sensitive images that we cannot afford to lose in lesser browsers then we have to provide a fallback solution.

We are currently investigating a Javascript loading solution, but I’ll write about that when we come to a decision. In the meantime, SVG is decorative images only.

Final thoughts

One thing we have learnt from taking an aggressive stance on using SVG in our products is not to let lesser browsers hold us back from embracing future-friendly technologies. As the seminal website dowebsitesneedtolookexactlythesameineverybrowser.com so elegantly communicates, no, they do not. If a lesser browser loses a decorative image but the website gains scalable images that will work for the foreseeable future then it is a implementation worth pursuing.

This post also appears on my website.

One comment:

  1. One plus point to using SVG sprites is that your visible page code is much cleaner and can be read more easily by other people working with your code. We can improve on this even more. 

Leave a Reply

Your email address will not be published. Required fields are marked *