Font icons rule. They’re easy to implement, well supported, and infinitely scalable without loss of quality. Even ol’ IE supports them! But there’s a downside: a font icon — like the letter A in a normal font — can only be one color.
Just one single color. Boring!
But what if I told you we can have colorful font icons like these?
The lion asked the
whale “Where did
parrot fly off to?”
These four critters are drawn by the talented Eva Galesloot and are recreated with good old font icons and some straightforward CSS. 1
But two colors ain’t enough, and polluted HTML just rustles my jimmies. So let’s try to come up with a cleaner method.
Four-color icons with basic CSS and webfonts
We’re going to use four different colors by transferring all the work to CSS and the font file. All we need on the HTML side is a span with the icon’s character set to the data-icon attribute:
After we’re done with the CSS and the font file, this turns into a colorful parrot:
Easy peasy! Let’s take a look at how this is done.
Step one: prepping the font file
The first step is to create the four glyphs we’re going to use in the font. For this we need an SVG for each color in the original design:
We need to assign these glyphs to four different characters in our font — for instance A, B, C and D. But this would result in an unwieldy data attribute, especially since we need to weasel a newline in there (the \a bit — more on that later):
So to keep the HTML tidy, we map each glyph to the same character in four different font files. This allows us to assign each one of them to a different font-weight. The parrot, for instance, is mapped to the letter p. The first font holds the first shape (the parrot’s body) and will be assigned to font-weight: 100. The next two fonts will be assigned to font-weight: 200 and font-weight: 300, and the last one to font-weight: 400.
The end result is four different font files, each file containing one layer for every icon. Loading four external files isn’t ideal, so I chose to base64 ‘em and combine them in one stylesheet. 2
I turned these into fonts by using Font Custom, but you could use a tool like Icomoon as well.3
Step two: putting CSS to work
We’ve created the font files, now it’s time to make those critters show up on our page and give them their appropriate position and color.
Remember, we’re working with just a single element. The drawback of not using extra HTML elements is that we can’t use selectors like :nth-child() to address individual characters with CSS. But there are a couple of CSS pseudo selectors we can use if we arrange our characters like this:
With all four layers properly styled, the last step is to overlap them. Since we’re not using real elements, we can’t use absolute positioning, so we summon the powers of negative letter-spacing and zero line-height to get the job done. And there we have it: four differently styled glyphs on top of each other!
This is the full CSS for the Skwirrol icon set:
Browser support, caveats and heads ups
This little trick works on all modern browsers I tested (Chrome, Firefox, IE11, Opera). I was surprised that it even works on all versions of IE upward from 8 (if you create an EOT file — for this demo I just stuck with WOFF).
Opera 12 and several mobile browsers have trouble showing these icons correctly. This seems to be caused by two main reasons: no font-face support at all, or more obscure differences in implementation of things like letter-spacing. Opera 12, for instance, doesn’t like letter-spacing: -1em (-0.99em is fine, though). A solution to this would be to create zero-width glyphs in your font, which is entirely possible and supported but outside the scope of this little hack.
Some other things to keep in mind:
Some browsers are picky about what exactly constitutes a :first-letter. If you use Unicode private area chars, these might be considered non-letters and won’t be styled with :first-letter.
The edge of the vector image will be anti-aliased by the browser, and each one does this in a slightly different way. Keep this in mind where glyphs touch or overlap — the bottom one might shine through at the anti-aliased outline of the glyph on top of it. You can prevent the page’s background color from seeping though by using the full design’s contours for the first glyph, like I did with the parrot’s body.
The icons should have a consistent bounding box across all fonts. This greatly simplifies alignment and sizing. I do this by including a control character in all the font files.
Souping up the semanticism
I’ve taken a bit of a poetic license with the title of this post, and some of you have rightly pointed out an empty span isn’t all that super semantic. So, here’s a variation of the hack, which’ll work with the following HTML:
You can now inject just two p values into the :before, and use the content of the span for the third p. The rest of the word will be chopped off by a simple overflow: hidden. The end result is the same, but now the HTML is truely semantic.
(Screen readers would read “ppparrotp” though, and when @font-face isn’t supported you’d have to undo this hack — otherwise visitors would see four overlapping ps instead of the parrot or the word “parrot”. Web crawlers and Lynx users will properly read your site now, though!)
Edit: This solution doesn’t work in IE11. Looks like overflow:hidden is the culprit. Anybody know what’s going on here?
And that’s that
And there you have it — a sweet little trick to get multicolor font icons. Is it a hack? Are you probably better off with SVG? Did I have a lot of fun squeezing extra colors out of a limited technology? Why yes, probably and yes!
Feel free to dig into the code on Github or Codepen! Let’s bring some color to font icons!
Fun fact: when I contacted Eva Galesloot if I could use her colorful icons, she pointed me to front-end hacker Rafal Bromirski who recreated these exact same icons in pure CSS3! ↩
You can reduce the number of files to two if you also use lowercase and uppercase letters. ↩
Be sure to include a control character that represents the widest width and the highest height of all the designs combined, so each font will have the same bounding box. If they don’t, your glyphs will vary in width and height and won’t align properly. Font Custom needs some extra work because otherwise a line feed will show up as missing glyph. Drop me a message if you need help ! ↩