Speed Patterns octocat github link burger menu

Enhance Fonts As They Load

By Sergey Chernyshev · · Assisted by AI

Custom web fonts are a powerful brand and design tool, but they cost the user time. A font file has to be downloaded, parsed and applied before any text styled with it can be rendered. Until then, the browser must decide what to do — and the wrong default ruins the reading experience.

The Problem: FOIT and FOUT

Browsers have historically picked between two unpleasant defaults:

Pure FOIT is the worse failure mode: the user can't even start reading. But a careless FOUT — a fallback font with very different metrics — is also painful.

Solution

Fallback text is legible from the first paint; the branded font swaps in once it loads, without leaving the user waiting on a blank page.

Two text panels side by side: the left in a system sans-serif labeled 'fallback (system)', the right in a serif italic labeled 'custom (loaded)'
System first, custom later

Treat custom fonts as a progressive enhancement, not a render blocker. Show legible fallback text from the first paint, then upgrade to the branded font when it arrives. Choose the fallback so the swap is as imperceptible as possible.

The strategy has three parts:

  1. Show fallback text immediately. Configure each web font so the browser uses a system fallback while the custom font downloads, instead of hiding the text
  2. Match fallback metrics to the custom font. Pick a system fallback whose size, ascent, descent and line-height align closely with the branded font, so the swap doesn't shift layout
  3. Prioritize which fonts get loaded urgently. Most pages don't need every weight and style up front. Subset, preload and self-host only what the first view actually needs

The first piece of legible text is what lets the user start reading. By showing fallback text immediately, you let reading begin at first paint instead of after a network round-trip. The brand fidelity arrives a moment later — at a cost of a small, near-invisible re-render rather than a blank page.

Guidelines

Related Patterns

Technical Implementation

Use font-display

The CSS font-display descriptor tells the browser how to behave while the custom font loads:

@font-face {
  font-family: "BrandSans";
  src: url("/fonts/BrandSans.woff2") format("woff2");
  font-display: swap;
}

Avoid the default (auto/block), which produces FOIT.

Match fallback metrics

When the swap happens, lines may rewrap, headings may shift, and Cumulative Layout Shift increases. Modern CSS makes this almost solvable:

@font-face {
  font-family: "BrandSans";
  src: url("/fonts/BrandSans.woff2") format("woff2");
  font-display: swap;
  size-adjust: 102%;
  ascent-override: 95%;
  descent-override: 22%;
  line-gap-override: 0%;
}

Tools like Fontaine and Monica Dinculescu's Font Style Matcher help find values that make a system fallback nearly indistinguishable in metrics from your branded font.

Preload and use modern formats

Resources