Preloading optional fonts to avoid FOIT and layout shift

Starting in Chrome 83, combining <link rel="preload"> with the CSS font-display: optional property can completely eliminate layout shifting caused by custom web fonts. The update optimizes rendering cycles so that optional fonts no longer produce a flash of invisible text (FOIT) or a visible swap from a fallback font.

Why custom fonts cause layout jank

Web fonts can trigger re-layout in one of two ways: a fallback system font is swapped out when the custom font loads (a flash of unstyled text), or text remains invisible until the webfont is rendered (a flash of invisible text). The font-display property in CSS controls this behavior through a timeline made up of three periods:

  • Block: Text renders as invisible, but switches to the web font when it finishes loading.
  • Swap: Text renders with a fallback system font, but switches to the web font when it finishes loading.
  • Fail: Text renders with a fallback system font and never switches.

Even with font-display: optional, which uses a 100ms block period and no swap period, Chrome would still re-render the page twice — once when the fallback is shown and once more if the custom font loads within the block window. That re-rendering produces a brief flicker of invisible text and potential layout jank, even when the font is already in the browser's disk cache and loads well within the block period.

The Chrome 83 optimization

Chrome 83 includes optimizations that remove the first render cycle entirely for optional fonts that are preloaded via <link rel="preload">. Rather than rendering with a fallback and then re-rendering, the browser now blocks rendering until either the custom font has finished loading or a timeout (currently 100ms) has elapsed. This matches the behavior specified in CSS Fonts Module Level 4: optional fonts should never cause re-layout, and the user agent may delay rendering for a suitable period.

Preloading an optional font is not mandatory, but it significantly improves the odds that the font will be available before the first render, particularly when it is not yet cached locally.

Browser support

Support for <link rel="preload">, font-display, and the rendering optimizations described here varies across browsers. See the MDN compatibility data for <link rel="preload"> and font-display for current details. Developers who encounter issues with preloaded optional fonts in Chrome can file a bug with the Chrome team.