If you really dislike FOUT, `font-display: optional` might be your jam

Avatar of Chris Coyier
Chris Coyier on

DigitalOcean provides cloud products for every stage of your journey. Get started with $200 in free credit!

The story of FOUT is so fascinating. Browsers used to do it: show a “fallback” font while a custom font loads, then flop out the text once it has. The industry kinda hated it, because it felt jerky and could cause re-layout. So browsers changed and started hiding text until the custom font loaded. The industry hated that even more. Nothing worse than a page with no text at all!

Font loading got wicked complicated. Check out this video of Zach Leatherman and I talking it out.

Now browsers are saying, why don’t we give control back to you in the form of API’s and CSS. You can take control of the behavior with the font-display property (spec).

It seems like font-display: swap; gets most of the attention. It’s for good reason. That’s the value that brings back FOUT in the strongest way. The browser will not wait at all for an unloaded font. It will show text immediately in the best-matching-and-available font in the stack, then if/when a higher-matching font loads, it will “swap” to that.

@font-face {
  font-family: Merriweather;
  src: url(/path/to/fonts/Merriweather.woff) format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;

body {
  font-family: Merriweather,   /* Use this if it's immediately available, or swap to it if it gets downloaded within a few seconds */
               Georgia,        /* Use this if Merriweather isn't downloaded yet. */
               serif;          /* Bottom of the stack. System doesn't have Georgia. */

The people wanted their FOUT back, they got it. Well, as soon as font-display is supported in their browser, anyway. Right now we’re looking at Chrome 60+ as the only browser shipping it (which means it won’t be long for the rest of the Blink clan). It’s behind a flag in Firefox already, so that’s a good sign.

But what if you don’t particularly like FOUT?

One option there is font-display: fallback;. It’s slightly weirdly named, as it’s a lot like the default behavior (auto or block). The difference is that it has a really short waiting period (“font block period”), ~100ms, where nothing is shown if the font isn’t ready to go in that super short period, a fallback will be shown instead. Then the font has ~3s to get loaded and it will swap in, otherwise, it never will.

That seems pretty reasonable. What you’re preventing there is a late-term swap, which is when it’s the most awkward. Still that risk of FOUT though.

If you’d prefer that if the web font isn’t immediately available, to just show the fallback font and not ever swap to it, even after it’s downloaded. You can! That’s what font-display: optional; does. It still gives the ~100ms font block period (giving the font a fighting chance to show up on first page view), but after that, the fallback is shown and will not swap. Chances are, the font did ultimately get downloaded, and next page view it will be cached and used.

This is font-display: optional; in Chrome 60. With a clean cache, the page loads with the fallback font. The font is downloaded, but not used. Then with the cache primed, the second page load uses the font.

I’m fairly open minded here. I can see how font-display: swap; is ideal for the best accessibility of content. I’m no big fan of FOUT, so I can see the appeal of font-display: optional;. I can also see how font-display: fallback; kinda splits the middle.

Aside from the browser support being vital in making use of this, there is also the matter of web font providers supporting it. For example, when using Google Fonts default font loading methods, you don’t have an opportunity to use font-display because the @font-face blocks come from the Google-hosted stylesheets. There is an open discussion on that. There are ways to use Google Fonts with your own @font-face blocks though. Definitely consult Zach Leatherman’s guide.