Icon fonts aren’t evil, you just have to care


  1. The problem with SVGs
  2. Icon fonts
    1. Text antialiasing: unavoidable
    2. Better control over SVGs: not always needed
    3. Fetching failures and accessible fonts: fixable with care
    4. Screen reader accessibility: almost unavoidable
    5. File size: fixable with care

Recently I did a whole bunch of changes to the way this website works and one of them included replacing all SVG icons with an icon font. While doing research, I found Seren Davies’ talk as well as many other posts being against them. A lot of these concerns and issues are valid and multiple times I stopped that rework, but in the end I believe, with enough care, you could make them work almost perfectly.

The problem with SVGs

First, we have to get acquaintanced with why I wanted change: before the big rework, this website used SVG images for all icons. For quite a while I’ve added support for an alternative light theme, but ever since the beginning icons have been an issue.

How can you change the color, or more specifically, the internal styling of an SVG? You have a couple of options, if you include it with a normal <img> tag, as I was doing, you could do some magic with filters to change the exact color, though this is kinda difficult and browsers support filters since somewhat recently. This is a deal-breaker, because I care about older browsers and without that CSS property, icons become very difficult to see on the light theme.

Another option is to load it with an <object>, <embed> or <iframe> tag, though they all require JavaScript to edit the internal styling and have a lot of problems:

The final option is putting SVG images directly inline with the rest of the HTML. However, this also comes with it’s drawbacks:

Nevertheless, this is the best option and the one I was thinking about the most.

Icon fonts

The alternative is to create your own font, where you replace certain unicode symbols with your own custom graphics. It is universally supported, changing color is as easy as changing text, adding an icon somewhere is as easy as pasting a unicode character there and the font itself can be cached. Is this too perfect to be true? Yes, yes it is, there are quite a lot of caveats (outlined very well, with images, on this post by Chris Coyier).

Text antialiasing: unavoidable

At the end of the day, your icons are text, so they’ll be antialised. The result is them being more blurry. This is pretty much unavoidable, but in my limited testing, most of the time they aren’t blurry, and when they are, it’s never so bad that you start loosing detail.

Better control over SVGs: not always needed

This is true, you can make an SVG have multiple colors, you can add animations and since SVGs are images, styling is usually easier. However, I don’t have any desire to do either of these, in practice my icons are “extending” the surrounding text.

Fetching failures and accessible fonts: fixable with care

Now, to the big problem, what happens if the browser doesn’t fetch the font or if a dyslexic person changes it to something they find easier to read. This is one of the main issues, outlined in the aforementioned Seren Davies’ talk.

Unicode defines certain characters as part of so-called Private Use Areas (PUA), meaning those character won’t ever have a standard glyph (image) assigned to them and any font can define them freely. The effect is that on different fonts, such a character will appear as a completely different glyph, though most don’t define them at all, leaving you with a default blank square. This is horrible: if the font doesn’t get downloaded or if you need to change it to something you can actually read, you’ll get random irrelevant glyphs at best and blank squares everywhere at worst. To add insult to injury, icon fonts like font-awesome contain their icons almost exclusively in the PUA!

However, this all can be fixed, at least to an extent. The main tricks are:

  1. Adding text to every clickable option, where possible. For example, I changed my theme button from an icon to “Dark theme” or “Light theme” (depending on the current theme).
    Even outside this topic, having text instead of icons has many benefits, mainly making it easier for users to understand how to interact with the website.
  2. Putting important navigational and functional icons outside the PUA (and leaving decorational ones there). For example, on mobile devices my sidebar is put on the top, but as to not take too much space, it is “folded” up. To expand it, you need to click an arrow on the top-right corner of the page. Now, that arrow image is “mapped” to the standard triangle pointing up and down characters, so if the font doesn’t load or is changed, you would get a triangle, which conveys the same action.
    This isn’t always possible though, for example, what if you have a company logo of some sort? The solution is in the previous point: don’t make your link to that company a single icon, at least add the name next to the icon (or in other words, make the icon decorative).

But, to do the second trick, you would need your own custom font. Thankfully, there are programs which can edit already existing ones, so you won’t have to know how to make one yourself. I personally really like tabler-icons (and more specifically, version 2.10.0) and for the editing I use FontForge. So, I download the .ttf version of the font and then a (part of a) FontForge script I made moves glyphs from the PUA to standard characters.

Screen reader accessibility: almost unavoidable

Text readers usually struggle quite a lot with Unicode characters and especially with those in the PUA. Generally, you have accessibility attributes like aria-label, where you can explain what the given character does. But SVGs have a title and description tags built-in, existing inside the image file itself, which is way better than adding an aria property.

File size: fixable with care

When every icon is on a separate image, you’ll download it only when needed, however with a custom font, you’ll always need to download the whole font, which includes icons you don’t use. For the aforementioned tabler-icons, the .ttf font file is 1.8 MB! That is waaaay too much, especially since the font could block rendering of the page. But in reality, if you remove the icons that you don’t use, the size difference could actually go in favor of fonts.

In the first half of my FontForge script I select everything that isn’t the 16 icons I actually use, and remove it. The same tabler-icons, but exported as (very well optimized for size) SVG files took up ~28KB in total, however the font with only those same icons was ~7KB in size. In reality, the most icons loaded by a page (/assets) totaled ~22KB in size, which is still a ~3 times reduction. On average a page probably requests less than 7KB of icons, but still, 7KB isn’t that much and once you fetch it, it get’s cached and you don’t have to request it ever again.

Overall, I would say size-wise, with a font containing only what you need, it could easily take up less space than the separate SVGs. If you still have speed issues, there are always ways to load fonts progressively.

Overall, even with a lot of customization, icon fonts could still sometimes cause issues for accessibility and are more limited in some ways. For me, I’ve found that their negatives (when applicable) don’t degrade website usage that much and their positives make my life a whole lot simpler.