CSS-Tricks
treehouse : what would you like to learn today?
Web Design Web Development iOS Development
Show search box
Search in: All Articles Forums Snippets Videos โœ•

HTML for Icon Font Usage

Published by Chris Coyier

Where are we at right now in terms of the best markup for using icon fonts? Let's cover some options I think are currently the best.

  1. You want the icon to enhance a word
  2. You want the icon to stand alone but still be functional or informational

And our major goals here are:

  1. As good of semantics as we can get
  2. As little awkwardness for screen readers as possible

This ground has been treaded before, but I think the following techniques are a small step forward.

Enhancing a word

Let's say we have a header like "Stats" and we want to set it apart from other headers on the page and emphasize it's meaning. Semantic ideal:

<h2 id="stats">Stats</h2>

Result:

spacer

So to get that icon in there (remember we're talking font icons here, we can't just pad the left and use a background) we'll need to insert some content.

Using a pseudo element is tempting because 1) they aren't read by most screen readers 2) we don't need dedicated markup for the icon which is a semantic ideal. Unfortunately, VoiceOver on OS X does read the content of pseudo elements. (reference 1, reference 2) Well, perhaps "fortunately" as if I'm reading the spec correctly that's what it is supposed to do. Psuedo elements just aren't in the DOM and thus that probably makes it harder for third-party apps to do.

The good news is that if we use a bit of markup, we can use aria-hidden attribute to prevent it from being spoken.

One more dash of bad news, even with aria-hidden on the markup surrounding the icon, VoiceOver on OS X will announce "HTML Content" when in focus. #dammit.

But alas! We can still win here. If we combine the markup technique and pseudo element technique, we can insert the icon with no VoiceOver weirdness. And as a double-win freebie, this combined technique is ideal for keeping our CSS lean and mean as it requires no class-name-bloat and works well with the next use case we need to cover.

So the final markup for this becomes:

<h2 id="stats">
  <span aria-hidden="true" data-icon="&#x21dd;"></span>
  Stats
</h2>

And the CSS is:

[data-icon]:before {
  font-family: icons; /* BYO icon font, mapped smartly */
  content: attr(data-icon);
  speak: none; /* Not to be trusted, but hey. */
}

Holy cow that's easy eh? Notice we aren't using a specific class name for the icon (e.g. like .icon-stats or something), we're using a data-* attribute to hold exactly which character we want to insert. In our icon font, we map those special characters to the icon we want to use. I find this perfectly semantic and even future proof (you could always select uniquely down the line even if you change the character). But if you prefer class names, more power to you, that's fine and doesn't change this technique drastically.

We'll cover mapping characters at the end.

Stand-Alone Icons

Say we have an icon that is a link or in some way functional, but it isn't accompanied by any text. For instance, a shopping cart icon that you can click to go to your shopping cart. Hopefully that functionality is obvious visually, with some kind of rollover state or general design obviousness. But that functionality also needs to be audibly obvious.

Instead of crafting a totally new technique to deal with this (which I've dabbled with in the past) let's lean on what we've already started. A span that inserts the character with a pseudo element, and text that sits right next to it that we kick off the page visually.

<a class="#rss">
  <span aria-hidden="true" data-icon="&#x25a8;"></span>
  <span>RSS</span>
</a>

We need very little in additional CSS, just a little usability fix applied via class, and a toolbox class for hiding the text but leaving it accessible.

.icon-alone {
  display: inline-block; /* Fix for clickability issue in WebKit */
}
.screen-reader-text { /* Reusable, toolbox kind of class */
  position: absolute;
  top: -9999px;
  left: -9999px;
}

Hey, it works

View Demo

Update October 2012: I made a more proper demo comparing icon font usage with different techniques.

In VoiceOver, anyway. Would be great to hear from people who use other screen readers how this holds up.

Building / Mapping Your Icon Font

One "issue" in the world of icon fonts right now is that the majority of them available come pre-mapped to letters. Used with improper markup, the letters become "content" and a part of the semantics of the document. Or worse, read outloud by screen readers.

It almost never makes sense for an icon to be mapped to a letter. Instead, I recommend mapping icons to the closest unicode symbol you can find. For instance, mapping a heart icon to โค is a splendid idea. The meaning of symbols is rather relative anyway, so close counts and will be a semantic improvement immediately.

Even better, I like the idea of mapping icons to the "Private Use Area" of Unicode. As I understand it, this is exactly why it exists, to use for your own special characters. Mapped this way, you're in no danger of the character being spoken by a screen reader. Unfortunately at the time of this writing icons mapped this way don't work in even the latest Safari, so it's not yet recommended. Here's the scoop on the Private Use Area issues paraphrased from Keyamoon:

There is a difference between PUA (Private Use Area) and SPUA (Supplementary Private Use Area). The difference is explained a bit here. In my testing, PUA mapping works perfectly in all browsers. SPUA mapping borks in Safari only on Windows. The IcoMoon app only maps to PUA, which is recommendable at least for the short term future.

Here are the steps to follow:

  1. Pick out an icon font.
  2. Go to IcoMoon and load it up (or use their icon set)
  3. Choose the icons you want.
    spacer
  4. Map them to the characters you want. Best to map to a relavant symbol or PUA.
    spacer
  5. Download the fonts/demo.

You can also use Pictos Server to do the icon-picking and mapping, but it only works with Pictos and doesn't help you with choose symbols (you could copy and paste from here). It is a very nice set though and hosts for you and makes it very easy to existing sets without manually swapping out font files.

The Future

In the future, hopefully we can rely on speak: none; working perfectly everywhere so we can go back to using pseudo elements and perfect semantics.

Relevant

View Comments

Comments

  1. spacer
    Akshay
    Permalink to comment

    Hey Chris, Thanks for this awesome read.

    I love your semantics, but never understand why you bother so much about screen readers. Do you have any stats about traffic from screen readers?

    • spacer
      Peter
      Permalink to comment

      I’d have to say it’s because you dont want to exclude anyone for any reason. It’s the same reason we all now must make mobile-first future-proofed responsive sites. So while your wordpress site may only get 1% mobile visitors now, that will increase. So much so that in the not-too-distant future, some folks may never own desktop computers and have their entire online experience through a mobile device…

      Oh yeah, and problem solving is fun.

    • spacer
      traq
      Permalink to comment

      In cases like this, the fact that the obvious/common solution “doesn’t work” points to a flaw in the solution: as Chris notes, the approach doesn’t actually work (the screenreader got it right: it’s just not what we wanted/expected).

      I can see why this would bug somebody, even if they didn’t care about screenreaders (not that we shouldn’t care about screenreaders).

    • spacer
      Tim Wickstrom
      Permalink to comment

      One Web Accessible to everyone should be everyone goal #imho

    • spacer
      Wes
      Permalink to comment

      Government sites yo…

      Most require some sort of 508 compliance, so even if they never get substantial traffic from screen readers they need accessibility standards.

    • spacer
      Matty
      Permalink to comment

      Screen readers are another way for users to interact with the content on our sites. Apart from the clear accessibility implications, we should be writing our code so that it caters for all people regardless of how they access it ( keyboard, mobile etc)

    • spacer
      Joeri
      Permalink to comment

      Funnily enough, the things you do to optimize for screen readers are, in most cases, also good practice in general.

  2. spacer
    Andru Stoicescu
    Permalink to comment

    Great topic, I always wanted to use font icons. You can do a lot of animations with them by only using CSS3

    • spacer
      Ben Peck
      Permalink to comment

      I’ve been in the same boat. I’ve used them with image generation tools before CSS could handle font embedding, etc.

      I’ve made a list of my favorite ones to date. If anyone knows of more please let me know. www.bentdesignstudio.com/v2/2012/05/icon-fonts/

  3. spacer
    Alexander Makarov
    Permalink to comment

    Service itself looks very familiar. See OpenSource fontello.com/

    • spacer
      Keyamoon
      Permalink to comment

      Just for the record, I must say that the older version of my tool was available even before the pictos server. And it was the first to allow building custom icon fonts. You can look at the changelog page in my site.

    • spacer
      Taufik Nurrohman
      Permalink to comment

      Bookmarked :)

    • spacer
      Vitaly
      Permalink to comment

      And fontello’s generated fonts are hinted. That can matter for small sizes.

    • spacer
      David Kaneda
      Permalink to comment

      It would appear the Icomoon fonts are hinted against 16 and 32px sizes at least… See the text justification and page-type icons for the clearest example.

      Great article Chris!

  4. spacer
    Carsten
    Permalink to comment

    Great article.
    I tried the PUA technique with Icomoon on my website.

    It works fine on :
    - All IE on PC
    - Chrome on PC and Mac
    - Firefox on PC and Mac
    - Safari 5.1.2 on Mac
    - Mobile Chrome (Android) and mobile Safari (iOS)

    It doesn’t work on :
    - Safari 5.1.2 PC
    - Opera every platforms

    • spacer
      Brannon
      Permalink to comment

      Have you tried it in webkit nightlies? Maybe it will be supported in Safari 5.2 PC.

  5. spacer
    Adverse
    Permalink to comment

    “Also, I’m sure eventually Safari will support PUA and we can map icons perfectly semantically as well.”

    Fingers crossed it happens soon. Great post. =)

  6. spacer
    Tim Wickstrom
    Permalink to comment

    Chris love the article but i think the pros/cons of using a class name lean in the favor of using a class.

    data-icon="⇝" – looks clunky to me

    where as class="stats" – makes more sense

    <span aria-hidden="true" data-icon="⇝"></span>

    becomes
    <span aria-hidden="true" class="icon stats"></span>

    And

    [data-icon]:before {
    font-family: icons; /* BYO icon font, mapped smartly */
    content: attr(data-icon);
    speak: none; /* Not to be trusted, but hey. */
    }

    Becomes:

    .icon:before {
    font-family: icons; /* BYO icon font, mapped smartly */
    speak: none; /* Not to be trusted, but hey. */
    }
    .stat {
    content: ⇝;
    }
    /* List of other classes here */

    I realize there is a bit more CSS but this most likely will be created once in the CSS and implemented countless times through out the web site/app.

    #IMHO

    • spacer
      James Peek
      Permalink to comment

      I agree with Tom, much easier to be able to identify what the font is when reading through HTML when it has a class to identify it by rather than an obscure unicode character, plus it makes reuse cleaner as I don’t have to refer back to my unicode mapping.

    • spacer
      Derek Erb
      Permalink to comment

      I haven’t tried this yet. But I just wanted to add that I certainly prefer being able to define the content in the style sheet rather than in the HTML. As my CSS files are always external this allows me to manage and modify the icon info without touching the HTML pages. If I have an icon in a menu, for example, then I would have to change each HTML page (data-icon=) instead of just changing the CSS file.

      Many thanks!

  7. spacer
    Keyamoon
    Permalink to comment

    I must clear up some confusion about Safari not supporting PUA. There is a difference between PUA and SPUA. See this Wikipedia page: en.wikipedia.org/wiki/Private_Use_(Unicode)#Private_Use_Areas

    PUA does not have any issues at all. But if you use SPUA, it won’t work in the Windows version of Safari.

    • spacer
      Carsten
      Permalink to comment

      Thanks Keyamoon, your font generator works fine on every browser and every platform with the PUA encoding.

  8. spacer
    Eduardo Shiota Yasuda
    Permalink to comment
gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.