Icon, but can you?

What’s the best way to embed SVG icons on my page?

March 29, 2017

A question on twitter made me think about the way we load one of the most used image assets on our pages: icons.

Are SVG sprites even a good idea? What about icon fonts? Does HTTP/2 support make a difference? What’s the best option when updating existing or adding new assets? What’s the fastest way of loading them? What’s the most flexible?

The question: “how do I add an icon/svg image to this <insert-element-name-here>” comes up with relative regularity at my workplace, and our current solution is to use an icon font when possible, a CSS background when not (we do not control the icon font we bundle, so certain icons are not available). I’ll only be taking vector-based icons into account here. Results for other formats will likely differ, as compression and loss may play a bigger role.

I considered the following ways to load icons:

  • use an icon font
  • use individual SVG files (<object>, <img> or background: url())
  • use a single SVG sprite file (<use xlink:href="images/sprite.svg#icon"></use>)
  • inline SVGs into the HTML document (inline <svg>; no referencing; no reuse on page without duplication)

All data was recorded using Chrome for Windows (Version 56.0.2924.87 - I should update that!) with “Good 3G” throttling enabled. The dataset used was the complete FontAwesome icon set. The code for this experiment is available on Bitbucket.

Here’s some pretty charts of my results:

Load times

Bytes served

Note: I’m pretty certain something’s off with the caching on HTTP2 here, but I didn’t look into it. By “off” I mean it’s probably not working.

Conclusion

For icons, use a CSS3 Webfont. It’ll be the quickest pretty much every time. The compression on the webfonts is hard to beat. If you need to play with the vectors on your icons, consider something like iconic’s SVG Injector. Sprites are interesting, since they perform reasonably well if you need to load a lot of images, but can’t use a Webfont. I think there are cases when you’d want to use a sprite, especially if you’re going to load a bunch of logos on the initial load; put all the stuff you really don’t want to pack into a font into a sprite. Also, it’s much easier to modify a sprite, since you can just chuck the SVG into the file and be done with it; no need to repack the font in every format.

For anything that’s not reused, like a “hero” image or empty state, try to just inline the SVG into an svg tag. If that’s not possible for some reason, try an img or CSS background will work too, but remember that loading each SVG is a server round trip.

By the way: In my example express handles all caching, so if you were looking for the answer to the twitter question, the answer is: most of the time don’t worry about it, the server will handle it based on changes to the file.