Trello uses an icon font and so can you!

January 31st, 2013 by Bobby Grace

Inspired by Github’s Octicons and a desire to clean up our kludgy icon code, I set out to convert trello.com to use an icon font.

Previously, we used an image sprite method. We used a single 750×145 pixel image that contained 6 versions of each icon (two sizes and three states). We offset each icon with CSS background-image and background-position. We also loaded a sprite at double the resolution and served it to higher DPI devices via media queries.

The sprite image looked like this:

Spriting is a popular and battle-tested method. So why switch? Icon fonts are a new, modern way to implement icons. They have tons of benefits, such as…

  • They are scalable and resolution-independent. There’s no need to cut a huge 2x size image for Retina displays. Notice how fonts automatically look nice on a Retina display without any media queries or additional CSS? An icon font will, too. It also scales properly for different zoom levels on the desktop, unlike our sprite method.
  • Icon fonts are smaller. Way smaller. We compile our entire CSS into a single file, which includes the embedded sprite image. We cut down that file from 118kb gzipped to 70kb gzipped, with the font embedded. The CSS is also cleaner and much easier to use.
  • You can use regular old CSS to alter color, adjust size, and add effects like shadows and gradients and whatnot. You no longer need to cut another image for hover states or different sizes.
  • They’re easily extendable since you can use one of the thousands of open unicode code points. You don’t need to shuffle much CSS either.
  • You can do stuff like thiisssss.

I was convinced, so I set out to do the conversion. I found all kinds of interesting posts, but none of them put it all together, so I decided to create a guide. Here’s how to design and implement an icon font for your own site.

The Tools

  • Glyphs. Glyphs is a font editor for Mac. It’s the nicest app for editing vectors I’ve ever used. If you’re just creating icon fonts, you can probably just use Glyphs Mini, but those developers deserve every cent for this excellent software.
  • Adobe Illustrator. We created our icons in Illustrator, so copying into Glyphs was a breeze. You may get along just fine with only Glyphs if you’re starting anew.
  • FontSquirrel @font-face Generator. we’ll use Font Squirrel to convert our font file into various formats.

Importing Glyphs into Glyphs

You can copy and paste Illustrator paths directly into Glyphs. There are a few pitfalls you’ll want to avoid, though. Glyphs default x-height is 500 points which translates to 500px if you’ve got Glyphs set to the default grid spacing of 1 (“File” > “Font Info” > “Other Settings”). Make sure your Illustrator object is about as tall as your x height, otherwise it may be a little hard to scale when it gets into Glyphs. Also be sure to use a solid fill in Illustrator. Using a gradient fill creates some funky points and curves. Other than that, just copy your paths and paste.

More on importing from Illustrator on the Glyphs blog.

Naming Glyphs

Underneath the surface, every glyph in a font has a unique Unicode code point. For example the capital letter “A” is 0041 in Unicode. You could map your glyphs to everyday characters like “c” (0063) or “m” (006D) so that your icons will appear when you use those characters in HTML, but Unicode has something specifically for custom extensions like ours. It’s called the Private Use Area, or PUA. The PUA is the 6,400 unassigned code points (E000 through F8FF) that are meant to be used by third parties so they don’t conflict with the standard Unicode assignments. Our glyphs are like no other glyphs, so it makes sense to use this range.

As an example, Apple uses the PUA to show the the Apple logo character  (F8FF). Neat.

To assign code points in Glyphs, click the top field in the bottom left pane, then name your glyph starting with “uni” then the code point you want to use. “uniE000″ or “uniF010″, for example. You’ll know you did it correctly when see the Unicode field at the bottom of the view change. The glyph will also go into the “Private Use” section instead of “Other”. After the unicode point is set, you might be inclined to change the name to something more human readable like “search” or “info”. Resist this urge. Changing the name from the uniXXXX format might mess up the names on export.

More on glyph names on the Glyphs blog.

For more on Unicode, read “The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)” on Joel on Software.

Hinting Hints

Our sprite image looked nice and crisp because every pixel was predefined and rasterized. All browsers, for the most, render images in the same way. Fonts are different. The browser is converting paths, points, and lines to pixels. A lot can get lost in the translation. Your font will be subject to various font rendering engines, some which will finesse smooth curves and some of which will churn out jagged edges.

Hinting is the practice of adjusting your vector paths so that they line up nicely when rendered on a rasterized pixel grid. It’s what you do to make sure your icons look sharp and crisp. You’ll spend a lot of time hinting your font, and it will take a lot of testing, tweaking, and eyeballing. Here are some helpful guidelines for you to get started, though.

Trello uses two icon sizes, one at 12 pixels and one at 20 pixels. Sticking to a roughly 60 pixel grid means the output will look sharp when it’s rendered at either size. You’ll want to set the width of your glyphs to 1920, a nice, round multiple of 60 pixels. Notice how the height, width, and positioning are all multiples of 60 in the screenshot below?

We also set the units per em to 1920. The what per what? An em is a unit of measure that, basically, describes how wide it is. The units per em is a measure of how much information gets packed into a character. Higher units per em will deliver more precise fonts, but require more processing. Click here to read Microsoft’s guidelines on type hinting and production. To change the units per em in Glyphs, open “Font Info…” (the “i” button in the top right corner), select the “Font” subsection and set your “units per Em” to 1920.

Your smaller icons may need dedicated glyphs that are specially hinted to do them justice. That’s up to you. You can also use different sizes, of course. The math works out more elegantly with 16 and 32 pixel sizes, for example. Set your “units per Em” to “2048″ (or 2^11) if you go that route.

In the end, our font looked like this:

Now that you’ve decided on your sizes and hinted the heck out of your glyphs, your font is complete! Go to “File” > “Export” (or cmd-E), confirm, and you’ll have an OpenType (OTF) file waiting for you.

Converting into Multiple Formats

Browsers are picky, so we need lots of different formats to satisfy them all. Luckily there’s a tool out there that will convert OpenType files into all those formats for us. It’s called the FontSquirrel @font-face generator.

There are a few things you need to do here. First, add the font, then select the “Expert…” option below. (We are experts.) For formats, select TrueType, WOFF, EOT Compressed (if you need support for IE8 and below), and SVG. You can deselect everything in the “Fix Missing Glyphs” section. We won’t be using those.

By default, FontSquirrel won’t load glyphs in the Private Use Area. Since our font is entirely in that range, we want to make sure it’s included. To do so, select “Custom Subsetting…” in the Subsetting section. In “Unicode Ranges”, enter “E000-F8FF”. (That’s the PUA range, remember?) At this point, FontSquirrel will render a preview of all 6,400 characters in this range in the browser. This is kind of slow and you might assume your browser is broken, but it probably isn’t. Don’t be afraid. You’re an expert!

Did it work? Okay, good. You can also remove “-webfont” from the “Font Name Suffix”, unless you want your files to look like mycooliconfont-regular-webfont. You should reconsider the name My Cool Icon Font, too, actually. Next, set the “Em Square Value” to “1920″, or whatever you had your “units per Em” set to (see the Hinting Hints section above). Now click “Download Your Kit” and you’ll get a .zip file containing all the formats we need. This can also take a few seconds since FontSquirrel is basically performing a miracle for us.

Want to automate this conversion business? Check out fontforge. I can’t tell you if this actually works because I never tried, but I think it’s possible. Go figure it out.

Loading Your Font

Now that you’ve got your font in all the requisite formats, you’ll need to load them via CSS. We’ll use @font-face for that. If this sounds new or scary, it’s neither. @font-face has been around since IE4 and is supported in nearly every browser. Not all browsers support every font format, but we’ll get to that in a second. The code for loading fonts looks like this:

@font-face {
    font-family: 'Trellicons';
    src:
        url('/static/fonts/myfont-webfont.eot?#iefix') format('embedded-opentype') 
            /* This is a hack for Internet Explorer 8 and 
               below (oldIE), which can't handle multiple
               src declarations. See this Stack Overflow answer for more. 
               Also, you can delete this EOT line if you 
               don't need support for oldIE. */
        url('/static/fonts/trellicons-regular.woff') format('woff'),
        url('/static/fonts/trellicons-regular.ttf') format('truetype'),
        url('/static/fonts/trellicons-regular.svg#trelliconsregular') format('svg');
    font-weight: normal;
    font-style: normal;
}

Old Internet Explorer will load the embedded OpenType file (EOT) file, and most other browsers will use the WOFF file. WOFF, or Web Open Font Format, files are basically wrapped OpenType (OTF) and TrueType (TTF) files with the additional benefit of compression and extra metadata. The Android browser and older versions of iOS will use TTF, and SVG will cover any other cases.

A note about SVG. While my Mac was nicely rendering the WOFF font, I discovered Windows was not rendering so nicely. This was particularly true of Chrome on Windows, which uses its own font rendering engine. After reading this helpful Font Spring article I switched to SVG fonts, only to find that SVG fonts are not supported in Firefox or IE9+. So then I spent quite a bit of time hinting the font. Then I spent a lot more time hinting the font. It was a lot of work, but good hinting goes a long way. The icons look sharper across all browser and operating systems.

After all that, we ended up using WOFF for most browsers for a few couple reasons. First, the file was two and half times smaller than the SVG file (7kb compared to 18kb). Secondly, line height on SVG fonts behaves differently across browsers, which means the icons looked either too high or too low depending on the browser. We did end up using SVG for Chrome on Windows, since SVG fonts do not go through the default font rendering engine. They simply look the best. We load the font conditionally by adding CSS classes for the browser and operating system to the body element of the HTML via some JavaScript and User Agent sniffing. (Note: this is bad and you shouldn’t do it.) This also allows us to fix the line height fix conditionally. The code looks like this:

@font-face {
    font-family: 'Trellicons Regular SVG';
    src: url("/static/fonts/trellicons-regular.svg") format("svg");
    font-weight: normal;
    font-style: normal;
}
.windows.chrome .icon-lg,
.windows.chrome .icon-sm {
    font-family: "Trellicons Regular SVG";
}
.windows.chrome .icon-lg {
    line-height: 34px;
}
.windows.chrome .icon-sm {
    line-height: 20px;
}

For more on @font-face and loading fonts, check out Paul Irish’s “Bulletproof @font-face syntax” and Font Spring’s “The New Bulletproof @Font-Face Syntax”.

Building Reusable CSS

Now that we’ve got our font loaded, we need to write some more CSS in order to use it. First, we’ll set up our two different sizes.

.icon-lg, 
.icon-sm {
    color: #b3b3b3; 
    display: inline-block; 
    font-family: "Trellicons"; 
    -webkit-font-smoothing: antialiased; 
        /* For more detail on this property, see Tim Van Damme's blog post. */
    font-style: normal;
    font-weight: normal;
    line-height: 1;
}
.icon-sm {
    height: 18px;
    font-size: 12px;
    line-height: 18px;
    width: 18px;
}
.icon-lg {
    height: 30px;
    font-size: 20px;
    line-height: 30px;
    width: 30px;
}

Now we need to go through and map the Unicode characters to CSS classes. In our font, the icon for organization is known as “F000″, the icon for board is “F002″, etc. We don’t want to write Unicode in our template every time. (Actually, we would have to write the HTML entity for the Unicode code point. Computers are awesome.) Luckily there’s an easy way to insert Unicode content in an element using only CSS. We’ll use “content” and the pseudo class “:before”. Here’s what it looks like:

.icon-org:before {
    content: "\f000";
}
.icon-member:before {
    content: "\f001";
}
.icon-board:before {
    content: "\f002";
}

Look, ma! No background-position! Now we can do:

<span class="icon-sm icon-org"/>

and…

<span class="icon-lg icon-board"/>

Ta-da! Now all we need to do is convert the CSS and templates to the new… Oh… This is going to take a while…

There are a few different ways to implement the CSS/HTML. Another neat approach is to use data- attribute, a method outlined in John Hick’s 24 Ways post. This will save on markup and is more semantically correct. Also see Chris Coyier’s example here. The class based method worked best for us since it’s most similar to our codebase.

So there you have it. Every step of the process and all the reading, all in one place. Should you choose to go on this adventure, I wish you good luck! I’m glad we took the plunge. It’s a faster, more succinct, and more scalable implementation. If you have any questions, you can ask me on Twitter.

And, oh yeah, go sign up for Trello! It’s the easiest way to organize anything with anybody.