Skip to main content

Using Icon Fonts

This article was updated on August 19, 2013 to reflect the current way I implement icon fonts on my projects, which now includes the use of a feature test.

Icon fonts are awesome, and if you’re not already using them on your projects, you should be.

Icon fonts are incredibly light weight. The one for this site is just 5kb in size. Because it’s a single font file instead of multiple images, it requires just one HTTP request, which is great for site performance. They can be scaled smoothly to any size, and styled easily using CSS.

Here’s how I implement icon fonts on my projects…

Creating the font

There are a lot of icon fonts available, but I use IcoMoon. The free version contains more than 300 icons, with paid versions offering over 900.

More importantly, though, IcoMoon also offers a free app that lets you build your own custom font. This means you’re only using the icons you need, which keeps the file size down.

Full Disclosure: Because I talk about this app so much on Twitter, the guy behind IcoMoon offered me a free upgrade to their Ultimate Pack. I love the app so much that I paid for it anyways, and I had purchased the Essential Pack months ago.

To get started, head over to the IcoMoon app and select the icons you want. When you’re done, click the “Font” button at the bottom of the screen to open the font generator.

Before you download your font, you’ll want to reset the encoding to Private Use Area. This is section of unicode that has not been assigned any characters. Using the private use area for your icons helps ensure that screen readers don’t read them aloud.

The alternative would be to use standard characters (a to z, numbers, etc.). This can cause screen readers to say things like, “z Twitter,” which isn’t good for accessibility.

Once you’ve reset the encoding, click “Download.”

Adding the Icons to Your Site

When you unzip the download file, you’ll find a few items. The ones we really care about:

  1. The font folder.
  2. The style.css file.

Upload the files to your site

Open up your favorite FTP client, and copy the “fonts” folder into the same directory as your CSS file. If you need to put it somewhere else, that’s ok. You’ll just have to change a few lines of code in your CSS file.

Now, open up your stylesheet and add a new section for icons.

Embedding the font

Open up “style.css.” At the top, you’ll see this code:

@font-face {
font-family: 'icomoon';
    src:url('fonts/icomoon.eot');
    src:url('fonts/icomoon.eot?#iefix') format('embedded-opentype'),
        url('fonts/icomoon.svg#icomoon') format('svg'),
        url('fonts/icomoon.woff') format('woff'),
        url('fonts/icomoon.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
}

This tells browsers where to find the files for the font-family IcoMoon, and what the default style and weight are.

You’ll notice there are four different file types listed. Unfortunately (but not surprisingly), not all browsers support the same file type, so it’s necessary to include a few. You’ll also notice that eot is listed twice. This is to fix an issue with older versions of IE (again, big surprise).

I prefer to see SVG listed last, as it’s typically a bit bigger than the other filetypes and often not as well hinted. It’s used for iOS, which cannot load any of the other types.

After moving SVG to the end, your code should like this:

@font-face {
    font-family: 'icomoon';
    src:url('fonts/icomoon.eot');
    src:url('fonts/icomoon.eot?#iefix') format('embedded-opentype'),
        url('fonts/icomoon.woff') format('woff'),
        url('fonts/icomoon.ttf') format('truetype'),
        url('fonts/icomoon.svg#icomoon') format('svg');
    font-weight: normal;
    font-style: normal;
}

Add it to your CSS file.

Note: If you copied the “font” folder to a location other than where your CSS file is located, you’ll need to change the URLs in the @font-face declaration accordingly.

Update on 5/31/2013: In the comments, Nigel Anderson asked how many of these files are downloaded by the browser (and how that could impact performance). The answer: Browsers only download the first supported file in the list, even if they support more than one file type.

Creating a class

There are two ways to include an icon font in your HTML. One involves adding data-icon= and then the character for your icon to an HTML object.

The second method, which I prefer, is to assign a class to the icon font. Rather than remembering character values, you can add a Twitter icon, for example, by adding class="icon-twitter" to an HTML object.

IcoMoon gives you the option to use either method, but since the second is easier, let’s use that.

You’ll see the following code in the “style.css” file:

/* Use the following CSS code if you want to have a class per icon */
[class^="icon-"]:before,
[class*=" icon-"]:before {
    font-family: 'icomoon';
    font-style: normal;
    speak: none;
    font-weight: normal;
    -webkit-font-smoothing: antialiased;
}

This says that any class that begins with icon- should use the IcoMoon font family, has a style and weight of normal, and should not be read aloud by screen readers.

You’ll notice that it also includes the webkit prefixed font-smoothing property. This improves the clarity of the font. For good measure, I also include a non-prefixed version and text-rendering: optimizeLegibility;, which improves kerning on Firefox and newer version of Internet Explorer.

The final version of your code should look something like this:

/* Use the following CSS code if you want to have a class per icon */
[class^="icon-"]:before,
[class*=" icon-"]:before {
    font-family: 'icomoon';
    font-style: normal;
    speak: none;
    font-weight: normal;
    -webkit-font-smoothing: antialiased;
            font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

Copy that into your CSS file below your @font-face declaration.

Naming the icons

Next, we need to associate the individual icons with their unicode characters. IcoMoon does all of the heavy lifting here, creating human-readable classes for the icons.

In this example, I created a simple font with three icons: Twitter, Facebook, and Dribbble.

The “style.css” file contained this code:

.icon-twitter:before {
    content: "\e000";
}
.icon-facebook:before {
    content: "\e001";
}
.icon-dribbble:before {
    content: "\e002";
}

You’ll notice that we’re using the CSS3 :before selector. This inserts the specified content before whatever HTML object the class is applied to. The content property is used to define the unicode character.

You can copy this code directly from “style.css” (without any modifications) into your CSS file.

Using icons in your HTML

Now that you’ve done all that, including icons in your HTML is insanely easy.

Using my example font above, if I wanted to include a Twitter icon on my site, I would just add <i class="icon-twitter"></i> to my HTML.

I use the <i></i> tags because they’re small, no longer used for italics, and there’s something logical about “i is for icon.” Also, it’s what they do in Twitter Bootstrap.

Update on 5/24/2013: In the comments, Michael Barrish correctly points out that <i> is still a perfectly valid HTML element. What I meant to say was that the newer <em> element is the preferred way to italicize, because it carries not just stylistic but semantic meaning. Accordingly, I use <i> for my icons.

Don’t forget to leave a space between the tag and the supporting text. For example, use:

<i class="icon-twitter"></i> Twitter

Not:

<i class="icon-twitter"></i>Twitter

Styling icons

Because the icons are a font, they will inherit the styling of their parent container by default. However, you can apply additional styling using CSS.

For example, if you wanted all icons to have a shadow, you could add the text-shadow property to [class^="icon-"]:before, [class*=" icon-"]:before. You can also add gradients, hover effects, CSS3 transitions and more. One limitation: the icons can only be a single color.

I like my social media icons to have branded colors, but still display the default hover behaviors. Here’s the code I would use to achieve that with the Twitter icon:

a .icon-twitter {
    color: #41b7d8;
}

This code says that when a Twitter icon is used in a link, it’s color should be #41b7d8, which is Twitter blue.

In my base CSS, links on hover turn black darken and are underlined. With the code above, the icon would still be underlined, but would be Twitter blue. We can fix this by adding a hover color:

a .icon-twitter {
    color: #41b7d8;
}
a:hover .icon-twitter{
    color: #005580;
}

Branded colors

While by no means comprehensive, here’s a list of popular social site colors to get you started.

Accessibility considerations

Icon fonts are typically not read by screen readers. For accessibility reasons, you should not rely on the icon alone to convey meaning.

There’s a simple CSS class you can use to include supporting text in your HTML but position it off screen. If you wanted to display a Twitter icon, for example, you would use this code:

HTML

<i class="icon-twitter"></i> <span class="screen-reader">Twitter</span>

CSS

.screen-reader {
    position: absolute; 
    top: -9999px; 
    left:-9999px; 
}

Because the text wrapped in the .screen-reader class is still displayed, screen readers will detect it in the HTML and read it out loud. But because it’s positioned off screen, sighted users will not see it.

Browser support

Icon fonts work in Firefox, Chrome, Opera, Safari and the latest versions of Internet Explorer back. They work in iOS and Android, but not Opera Mini. Strangely, they don’t work in IE9 on Windows Phone 7. This has been fixed in Windows Phone 8.

While @font-face embedding has been supported since IE 5, the approach detailed in this article uses pseudo selectors to include icons in the HTML, and that’s only supported back to IE 8. IcoMoon includes a JavaScript file named lte-ie7.js that’s supposed to provide support for older browsers, but I’ve never gotten it to work, and several others have mentioned running into issues with it in the comments section.

I treat icons as a progressive enhancement, and use a simple feature test to check for support.

Feature test

Browsers that don’t support @font-face will sometimes display empty boxes where the icons should go. This looks ugly and can sometimes overlap with text, making it difficult to read. I use a simple JavaScript feature test to check for @font-face and pseudo selector support.

Download the script from GitHub and include it in your <head> element:

<script src="font-face-feature-test.js"></script>

This adds a .font-face class to the <html> element when both @font-face and the :before pseudo selector are supported. In my CSS file, I prefix the icon names with that class, so that they’re only activated when a browser has the proper support:

.font-face .icon-twitter:before {
    content: "\e000";
}
.font-face .icon-facebook:before {
    content: "\e001";
}
.font-face .icon-dribbble:before {
    content: "\e002";
}

You can also use this class to change what content is displayed based on whether or not the browser supports icon fonts. For example, you might show an icon for supporting browsers, and plain text for older browsers. Here’s an example:

HTML:

<span class="if-font-face"><i class="icon-twitter"></i> <span class="screen-reader">Tweet This</span></span>
<span class="no-font-face">Tweet This</span>

CSS:

.if-font-face,
.font-face no-font-face {
    display: none;
    visiblity: hidden;
}

.font-face .if-font-face {
    display: inline;
    visibility: visible;
}

Using icons today

Despite these considerations, icon fonts are very well supported, highly-flexible, and ready to be used on web projects today. Their small size and crisp resolution make them a versatile addition to responsive web development.

Referenced & Useful Resources

  1. IcoMoon
  2. Icon Fonts are Awesome by CSS-Tricks
  3. Trent Walton on why he switched to icon fonts
  4. Typekit on Windows Phone 8 Support

Have something to say? Let me know on Twitter at @ChrisFerdinandi, or send me an email.