Remember FOUT? When using a custom font via @font-face, browsers used to display a fallback font in the font stack until the custom one loaded. This created a "Flash of Unstyled Text" — which was unsettling and could cause layout shifts. We worked on techniques for fighting it, for instance, making the text invisible until the font was ready.

A number of years ago, browsers started to shift their handling of this. They started to detect if text was set in a custom font that hasn't loaded yet, and made it invisible until the font did load (or X seconds had passed). That's FOIT: "Flash of Invisible Text". Should a font asset fail or take a long time, those X seconds are too long for people rightfully concerned about render time performance. At worst, this behavior can lead to permanently invisible content.

These days we're trying to fight against FOIT in various ways. In Faster Font Loading with Font Events, Jonathan Suh suggests using a library to detect if a custom font has loaded, and only then change a class name on the document to set the text in that font. This makes the behavior like FOUT - speeding up readable content at the cost of somewhat jarring visual changes.

Zach Leatherman has been writing a lot about this too. In Better @font-face with Font Load Events he also suggests waiting for the font to be loaded before setting a class to set the type. He also goes into what it takes to trigger a font download (it's not as simple as a @font-face declaration). Scott Jehl corroborates this in Font Loading Revisited with Font Events, including a bit about cookies and caching.

Zach's latest trick involved FOFT: "Flash of Faux Text". The idea here is only waiting for the Roman variant of the custom font to load, and setting text in that right away. You force the browser to create "faux bold" and "faux italic" where needed, which are replaced by the real versions as soon as those are downloaded.

Vitaly Friedman wrote about their approach on Smashing Magazine where they actually use localStorage to cache the font. It ends up being like FOUT on the first page load and (a fast) FOIT on subsequent loads.

I just think it's interesting how we flip around on this stuff every so often. The browser behaves one way and we trick it into behaving another way. It changes to that way, and we trick it into behaving the old way.