Icon systems for the web - an in-depth guide
Tags: webdev, html, css, beginners
Published: 2019-10-22 05:24:03

---
title: Icon systems for the web - an in-depth guide
published: true
description: 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.
tags: webdev, html, css, beginners
cover_image: https://thepracticaldev.s3.amazonaws.com/i/7btjgiwo3y4gmq5pt7wz.png
---

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](https://thepracticaldev.s3.amazonaws.com/i/om1gobpwqw6ojx2mvf4k.jpg)
<figcaption>Spritesheet example</figcaption>

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](https://modernizr.com/) 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:

```html
<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):

```css
.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.

{% link https://dev.to/adrianbdesigns/accessibility-hiding-content-30of %}

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](http://www.spritecow.com/) - Online spritesheet image and CSS generator
* [PostCSS-lazysprite](https://www.npmjs.com/package/postcss-lazysprite) - PostCSS plugin for automating spritesheet image and CSS generation
* [gulp-svg-sprite](https://www.npmjs.com/package/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:

```css
/* 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:

```html
<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](https://icomoon.io/) - manage and generate icon font file & CSS
* [fontello](http://fontello.com/) - manage and generate icon font file & CSS
* [icon-font-generator](https://www.npmjs.com/package/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:

```html
<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:

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

We can implement PNG fallback for older browsers by using `srcset`:
```html
<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)

##Bonus: Image optimization

I've mentioned how image file size optimization can improve download and loading times. If you are interested in learning more about image file size optimization, check out this article.

{% link https://dev.to/prototyp/optimizing-images-for-the-web-an-in-depth-guide-4j7d %}


## Community poll

What is your favorite go-to choice when implementing icons on the web? Let me know by submitting your vote on the following Twitter poll.

{% twitter 1186513577290674177 %}

<hr />

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.

<a href="https://www.buymeacoffee.com/ubnZ8GgDJ" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-red.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></a>

Thank you for taking the time to read this post. If you've found this useful, please give it a ❤️ or 🦄, share and comment.