Icon systems for the web - an in-depth guide

Icon systems for the web - an in-depth guide

Adrian Bece

Published on Mar 29, 2021

11 min read

Subscribe to my newsletter and never miss my upcoming articles

If you have enjoyed reading this article, please give it an upvote on Daily Dev. Much appreciated!


Icons are commonly used elements on the web. They are universal, instantly recognizable, can be very appealing, draw attention, and (if used correctly) provide a great user experience.

We have quite a few options when implementing icons on the web:

  • Icon Spritesheet
  • Icon font
  • Inlined SVG
  • SVG as an image element

Some of them are more commonly used today, like SVG elements and Icon fonts. In this article, we're going to dive deep into each approach of implementing Icons on the web and see which approach is the best in terms of performance, accessibility, styling options and browser support.

Icon Spritesheet

We create an Icon Spritesheet by combining smaller image (icon) files into a single, larger file. We need to use CSS background-image, background-size and background-position to display the image from the spritesheet.

Icon spritesheet example

Spritesheet example

We can use SVG spritesheet to ensure that icons look great on various displays (regular and retina) in combination with PNG spritesheet as a fallback for older browsers. We can use a JavaScript library like Modernizr to detect if the SVG is supported on the user's browser and provide a PNG fallback if SVG is not supported.

Let's create an accessible icon:

<span aria-hidden="true" class="icon icon--email"></span><span class="hidden--visually">Send me an Email</span>>

Spritesheet CSS example (Can be generated or manually added):

.icon {
  background-image: url('../images/spritesheet.svg');
  background-repeat: no-repeat;
  display: inline-block;
  width: 64px;
  height: 64px;
}

.no-svg .icon {
  background-image: url('../images/spritesheet.png');
}


.icon--email {
  width: 64px;
  height: 64px;
  background-position: 0px 0px;
}

If you are wondering about the hidden--visually CSS class and how to accessibly hide content, I've explained it in more detail in one of my previous articles.

Let's review the pros and cons of using icon spritesheet.

Pros:

  • Process of adding icons can be easily automated
  • Image optimization techniques can reduce the spritesheet file size
  • Works well on all displays (when SVG spritesheet is used)
  • Great browser support (when PNG fallback is used)
  • Reduced number of requests (useful when HTTP/2 is not used)

Cons:

  • Not accessible out of the box. Accessibility needs to be manually added with additional HTML elements.
  • Poor styling option
  • All variations of the icon need to be added as a separate element in the spritesheet
  • Conflicts can happen if multiple people add new icons to it at the same time
  • No performance benefits when using HTTP/2

Tools:

  • Sprite Cow - Online spritesheet image and CSS generator
  • PostCSS-lazysprite - PostCSS plugin for automating spritesheet image and CSS generation
  • gulp-svg-sprite - Gulp plugin for automating spritesheet image and CSS generation

Icon font

Instead of combining our icon image files into a single image file, we can generate font files that will contain our icons. Browsers will treat them as text and they can be easily customized with text styles.

There are numerous tools that make generating icon font files and a CSS file very easy and manageable. Generated CSS file can look something like this:

/* Define font icon font family */
@font-face {
    font-family: 'myIconFont';
    src: url('/path/to/myIconFont.ttf?r9c57c') format('truetype'),
        url('/path/to/myIconFont.woff?r9c57c') format('woff'),
        url('/path/to/myIconFont.svg?r9c57c#myIconFont') format('svg');
    font-weight: normal;
    font-style: normal;
}

/* Define icon class that sets font family and shared font styles */
.icon {
    font-family: 'myIconFont';
    speak: none;
    font-style: normal;
    font-weight: normal;
    font-variant: normal;
    text-transform: none;
    line-height: 1;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Define individual icon class that inserts the icon as a character in pseudo-element */
.icon--email::before {
    content: '\e900';
}

We can use the similar markup to crate an accessible icon:

<span aria-hidden="true" class="icon icon--email"></span><span class="hidden--visually">Send me an Email</span>>

Let's review the pros and cons of using font icons.

Pros:

  • Good optimization options
  • Easily editable and generated with various tools
  • Great browser support
  • Really easy and convenient to use

Cons:

  • Font anti-aliasing might cause an issue with icon rendering
  • Nothing is displayed while font file is downloading and loading
  • Can easily be overridden if a user is using specific font or style override
  • Not accessible out of the box. Accessibility needs to be manually added.

Tools:

  • icomoon - manage and generate icon font file & CSS
  • fontello - manage and generate icon font file & CSS
  • icon-font-generator - NPM plugin for generating icon font from SVG icons

Inline SVG icons

Instead of including some file (spritesheet or icon font) and adding an icon into our markup with CSS, we can directly insert SVG data into HTML document and the browser will parse and display the SVG element. Inline SVG elements are highly customizable because we can even style the individual SVG element.

Let's take a look how an accessible icon using inline SVG looks like:

<svg labelledby="titleId descId" role="group">
    <title id="titleId">Example title</title>
    <desc id="descId">Long description explaining this example</desc>

    <!-- SVG icon code -->
</svg>

We are using labelledby="titleId descId" with title and desc SVG elements to make the element accessible to an assistive device. It's also important to note that role="presentation" should be used on graphical parts of the SVG elements that should be ignored by an assistive device.

Let's review the pros and cons of using inline SVG icons.

Pros:

  • Loads with HTML document with no additional load time
  • No additional HTTP requests
  • Good accessibility support with no additional HTML elements needed
  • Looks great on various screens
  • Best in terms of styling options (can even style elements within the <svg> element)

Cons:

  • Complicates HTML document markup (depends on a framework that is used)
  • Hard to manage and maintain (depends on a framework that is used)
  • Icons are not cached
  • Some older (and less used) browsers are not supported

Note: Some frameworks make managing and maintenance of icons easier. For example, Webpack can convert all import MyIcon from "/path/to/myIcon.svg" into an inline SVG on a production build. So for dev, we have a simple markup that can be easily maintained.

SVG in image elements

Instead of having an entire SVG markup in HTML, we can keep the icons as separate files and use <img> HTML element to include it in our markup. This enables us to have a simple and maintainable markup and small file sizes. We can also use native accessibility features of the element for our icons.

Let's create an accessible icon using this approach:

<img src="email.svg" alt="Send me an email">

We can implement PNG fallback for older browsers by using srcset:

<img src="email.png" alt="Send me an email" srcset="email.svg">

Browsers that support srcset also support SVG elements and they will automatically load the SVG image. Browsers that do not support it will load the PNG fallback.

Let's review the pros and cons of using SVG in image elements.

Pros:

  • Simple markup
  • Built-in simple accessibility options with alt tag
  • Good browser support (if PNG fallback is used)
  • Image file size can be optimized
  • Image files can be cached (once downloaded)

Cons:

  • Poor styling options
  • Each variation of the icon (different color, for example) should be in a separate file
  • Each icon requires a server request (if not cached)

These articles are fueled by coffee. So if you enjoy my work and found it useful, consider buying me a coffee! I would really appreciate it.

Buy Me A Coffee

Thank you for taking the time to read this post. If you've found this useful, please give it some likes, share and comment.

If you have enjoyed reading this article, please give it an upvote on Daily Dev. Much appreciated!

 
Share this
Proudly part of