The BarbLog

Design, front-end dev and other random thoughts

Icon fonts: How to make your own

February 17, 2014 | Comment

This is the writeup to accompany my presentation slides about icon fonts.

Before we get into the ‘icon’ part of it…

If you use custom icon fonts, you will be likely embedding them using the @font-face CSS option. The most fail-safe way of doing so is by using the following syntax, as explained at first by Paul Irish and tweaked by Jon Hicks to arrive at this version:

@font-face {
font-family: 'Pictos';
src: url('pictos-web.eot');
src: local('☺'),
url('pictos-web.woff') format('woff'),
url('pictos-web.ttf') format('truetype'),
url('pictos-web.svg#webfontIyfZbseF') format('svg');

This is to ensure all browsers, including that pesky Internet Explorer, display the correct font files. Yes, that’s a smiley face there. Read the above articles to find out why!

Why use icon fonts?

Because they are awesome! There are four main reasons, though. Icon fonts are…

  • Scalable; as they are essentially vector files they will remain sharp at any resolution and size, unlike bitmap icons that will become pixellated when resized or viewed on retina displays.
  • Styleable; using CSS, we can manipulate their styling in the same way as we would with any text-based content, meaning we can change colours (on hover this means fewer extra images in a spritesheet), add text-shadow, font-stretch, and anything else you can do with text.
  • Speedy; one HTTP request takes care of bringing in all the icons you use on your website, so if you for any reason aren’t using a spritesheet this will improve your performance versus bitmap icons that would be downloaded one by one.
  • Small; the file size of the icon font is often smaller than the file sizes of a PNG or JPG equivalent of the same quality (and again, those would not be scalable).

 Making your own with IcoMoon

Despite the abundance of icon fonts (both free and paid) on the web, the main problem with them out of the box is that each font file contains lots of glyphs – most probably many more than you will ever need on your website. This bumps up their filesize. In addition, if you want to use glyphs from more than one font file you’ll need to load all the fonts separately, which means more HTTP requests, too. You also don’t really have the option of customising anything; you’re stuck with the glyphs available in those font files.

There are now tools to create your own icon font files though, allowing you to pick and mix glyphs from different sets, and even upload your own. The tool I found to be the best for this is IcoMoon, a handy little web app that has both free and paid tiers, with the free version probably suitable for most of us. It allows you to pick your glyphs from the many available fonts within the app, upload your own font files or upload your custom SVG glyphs, edit them if desired and compile all these into downloadable fonts.

You can export the icon set as an SVG and PNG spritesheet as well as a ZIP containing the font. If you choose the font option there is an extra page that allows you to specify the Unicode character references you want to use for each glyph, plus ligatures if required.

Adding the code

Let’s say we created an icon for a link to a profile page, the icon being a little face with the word ‘Profile’ next to it. We have mapped the icon glyph to the letter ‘p’ (meaning that if we type ‘p’ in that font, we will see the icon).

The unsuspecting newbie (to icon fonts or to web development in general) might consider implementing their new icon font like so:


<a href="profile.html">
   <span class="icon profile"></span>Profile


.icon {
font-family: "My Icon Font";
.profile:before {
content: "p";

This would be perfectly acceptable, if we only had to cater for sighted users. However, we need to consider those using screen readers to access our content. There is a varied selection of screen reader software out there, and not all of them work the same way. Certain ones will read the above as: “Link. P. Profile.”

While annoying or confusing, this is still the better experience for the user. If the word ‘Profile’ was not there, and we only used the icon to communicate the link’s purpose, all the user would hear from the screen reader is “Link. P.” which is certainly not acceptable. CSS has a


rule we could use, but not all screen readers will obey that so we cannot rely on it alone. Some will announce “HTML content” which is potentially even more confusing than if it just read the letter out.

Solution for decorative icons

This solution is for icons that have a text label next to them and are therefore mostly decorative in purpose. There are four steps to this process.

  1. Map your custom glyphs to code points in the Unicode Supplementary Private Use Area (plane 15 or 16 of the Unicode chart). This ensures screen readers can’t match them with any existing character names/pronunciation. It is also a way of keeping your code clean and not mixing random letters in there. For example, let’s map our profile icon to U+e000. (Note: you can do this without the Unicode part, and just use letters, but I think it is cleaner this way)
  2. Add the ARIA-hidden attribute to the HTML that will contain the icon. This ensures screen readers don’t read that content (but best not to rely on it 100%, hence the step after this).
    <span aria-hidden="true"></span>Profile
  3. Add an HTML5 custom data attribute to the span tag. The content should be HTML equivalent of the Unicode character reference of the glyph we want as the icon. In this case, &#xe000. Use this little converter if needed.

    <span aria-hidden="true" data-icon="&#xe000"></span>Profile
  4. Add the CSS, with the content of the data-icon attribute acting as the pseudo-element’s content.
    [data-icon]:before {
    font-family: "My Icon Font";
    content: attr(data-icon);
    speak: none;

This technique is used in this YouTube example by Keyamoon and as you can see, the icon content is not read out by the screen reader. IE7 and below don’t support pseudo-elements, but IcoMoon generates a polyfill for you if required.

Solution for standalone icons – option 1

The first solution builds on the custom data attribute solution described above. After implementing that, simply wrap the text label in a <span> tag and push it off the page with CSS:

.label {
  text-indent: -9999px;

This is simple but requires extra markup, and if your icon font fails for any reason you will be left with nothing on the page where the icon should be (because your label was pushed off the page).

Solution for standalone icons – option 2

The second option is the use of ligatures. This way, your text is your icon, no extra markup or CSS needed and if your font fails the text will still be there, still clickable. IcoMoon makes it very easy to configure as well. The downside to ligatures is that they are not supported in IE9 and below (Ian Yates describes a workaround via conditional classes), and may have issues on older versions of Opera, so make sure you test thoroughly before deploying this solution.

References and further reading

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>