font-display is Incompatible with Icon Fonts
There are myriad problems with icon fonts. I won’t rehash those again here but I did a section on this specific topic in The Scoville Scale of Web Font Loading Opinions. A bunch of people have written about this before:
- Delivering Octicons with SVG on the GitHub Blog.
- Seriously, Don’t Use Icon Fonts by Tyler Sticka for the Cloud Four blog.
- Death to Icon Fonts, a talk by Seren Davies
- Making the Switch Away from Icon Fonts to SVG: Converting Font Icons to SVG by Sara Soueidan
- Inline SVG vs. Icon Fonts by Chris Coyier on CSS Tricks
- Have another? Pass it along!
The main point that I think hasn’t really been communicated enough is that icon fonts exist in a place that would seem to be outside of the web standards mainstream. Specifically, the font loading poster child—the font-display
descriptor—has no valid value that is compatible with icon fonts.
When you load an icon font, you often never want the fallback text to render. It isn’t a typical Flash of Unstyled Text (FOUT) scenario. If the fallback text for an icon font renders, who knows what you might see.
If the icon font uses glyphs mapped to the Private Use Area, you may see emoji characters (this is a common failure scenario).
If the icon font uses ligatures, you could see the ligature text (which is better, but often also not handled very well).
Some browsers (Firefox) show a TOFU character as fallback.
An astute web font loading reader might reach for the easiest tool in the toolbox to solve font loading issues: the font-display
descriptor. However there are no good values for font-display
that will offer invisible text. In fact, a few of the values will be quite bad.
- Using
font-display: optional
on your icon font means that it will only render on repeat views and renders fallback text on empty cache views: Very Bad 🚫 - Using
font-display: swap
on your icon font means that it will render fallback text immediately while waiting for the web font to finish loading: Bad 🚫 - Using
font-display: fallback
will only render the icon font if it loads within a short (usually 3 second) time period: Not great 🚫 - Using
font-display: block
is the default behavior and will use invisible text for up to 3 seconds and show fallback text until the web font load completes: The best option but still not good 🚫
To workaround these issues, you could use the CSS Font Loading API to force invisible text until the icon font has successfully loaded. Or, perhaps more in line with the web standards mainstream, you could make a better investment and convert your icons to use SVG instead.
8 Comments
@knaackbuilt
It always hurts a little when a project has such a baked in reliance on icon fonts and you can’t prioritize the time to remove them 😬
@zachleat
Doing Our Best in 2022 (as a service)
@NudgeCloud
Font icons considered harmful.
@PixelAmbacht
Yep, no way to beat FOUT ifn't you use the JavaScript.
@gracesnow
I didn't know that! I don't like icon fonts but some legacy projects still have them. I didn't realise about font-display
@WestbrookJ
How do you feel about fonts that use ligatures instead of glyphs so that you can write <span class="icon-font">gear</span> so with `font-display: swap` it will say "gear" until the font loads it upgrades it to the gear icon?
@PixelAmbacht
It's a cute feature, but not a saving grace. It can cause serious layout reflow, and:
@zachleat
I think it also sidesteps mainstream i18n workflows, too