Inline SVG with Grunticon Fallback

Avatar of Chris Coyier
Chris Coyier on (Updated on )

Grunticon 2 is out! It’s got a cool new website. Grunticon is a damn fine tool for building an SVG icon system. The workflow is like:

  1. Have a folder full of SVG icons
  2. Run Grunticon on that folder, which produces everything you need
  3. Put the bit of JavaScript in the <head>
  4. Use HTML like <div class="icon-image"></div> where you want icons
  5. Icons everywhere!

Grunticon 2 even has a method for injecting inline <svg>, so that you have all those advantages, like scripting, animating, CSS control, etc. You just add an attribute:

<div class="icon-burger alt" data-grunticon-embed></div>

You’d be good using Grunticon just exactly how it is. It just is a bit of a different approach than the one I’ve been talking about a lot, which uses an SVG sprite and inline <svg><use></use></svg>.

The way I show it, you start with inline <svg> in the document where you want the icons, and handle fallbacks from there. The possible advantages to this are:

  • If inline SVG is supported, no DOM manipulation happens at all, everything is just left alone and works.
  • It’s a bit easier to rip out the fallback one day if you decide you no longer need it.
  • (Thanks to Scott pointing out below): Non-JS users would get SVG icons instead of fallback PNG if you chose not to Ajax for the sprite and just embed it in the document.

What’s cool about inline-<svg>-first is that we can still use Grunticon to help us with the fallbacks!

1. Get a folder full of SVGs + Make SVG sprite

You can get them in any possible way you get get/create SVG. We’ll use IcoMoon here because it’s easy and awesome and gives us the SVG sprite right off the bat. If you want to make sprite creation part of your build, read up.

2. Use the icons as normal in your document

Simple example:

<button>
  <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-home">
    <use xlink:href="#icon-home"></use>
  </svg>
  Go Home
</button>

Make sure to use the xmlns="http://www.w3.org/2000/svg" on them, which is required to give them layout in IE 8.

3. Use the normal Grunticon build

In the Gruntfile.js:

grunticon: {
  icons: {
    files: [{
      expand: true,
      cwd: "svg/",
      src: ["*.svg"],
      dest: "fallbacks/"
    }]
    // We don't need the enhanceSVG option here
  }
}

This produces all the PNG fallback stuff for you.

4. In the head of the document, run an inline SVG test

Modernizr has a great inline SVG test we’ll hijack.

var supportsSvg = function() {
  var div = document.createElement('div');
  div.innerHTML = '<svg/>';
  return (div.firstChild && div.firstChild.namespaceURI) == 'http://www.w3.org/2000/svg';
};

if (!supportsSvg()) {

  // Do Grunticon stuff

} else {

  // Ajax for SVG sprite

}

5. If the test says inline SVG is supported, Ajax for the sprite

We’ve covered this before:

var ajax = new XMLHttpRequest();
ajax.open("GET", "svgdefs.svg", true);
ajax.responseType = "document";
ajax.onload = function(e) {
  document.body.insertBefore(ajax.responseXML.documentElement,
                             document.body.childNodes[0]);
}
ajax.send();

This has nothing to do with fallbacks, this is just the normal process of fetching the icons in supported browsers. We do this so it works in IE 9/10/11 and we can browser-cache the sprite.

6. If the test says inline SVG is not supported, use Grunticon

It’s just ever-so-slightly modified in that you delete first CSS file in the grunticon() call. That’s the one where SVG is supported, and we already have that covered.

// Inline script of grunticon.load.js here
grunticon(["", "/fallbacks/icons.data.png.css", "/fallbacks/icons.fallback.css"]);

Seems to work pretty well

Modern browsers
Still happy in IE 9, falls back in IE 8 and Android well.

If you need IE 6 and 7 too…

As is, we’re using the <svg> element itself and setting a background on it as needed for fallbacks. IE 8 can do that, but IE 6 and 7 can’t. The SVG element will just disappear (even if you use the HTML5Shiv, weirdly enough).

If you’re in the position you need to support these ancient browsers, move the class names up to a wrapping div instead:

<div class="icon icon-credit">
  <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-arrow-right"><use xlink:href="#icon-arrow-right"></use></svg>
</div>

Another notable IE 6-7-8 issue: you don’t get background-size, so, generate the PNGs in the exact size you’re going to use them.

Repo

I tossed the concept up in a repo in case I screwed stuff up and y’all want to fix it.