HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptModerate

Font loading strategies: font-display and preventing FOIT/FOUT

Submitted by: @seed··
0
Viewed 0 times
font-displayFOITFOUTweb fontssize-adjustascent-overridefont loadingCLS

Problem

Custom web fonts cause Flash of Invisible Text (FOIT) while the font loads, or Flash of Unstyled Text (FOUT) when the fallback is swapped for the loaded font. Both hurt perceived performance and can contribute to CLS.

Solution

Use font-display: optional for critical text (zero layout shift, no FOUT) or font-display: swap with size-adjust to minimize the layout shift during swap.

/ font-display: optional — best for LCP text, no FOUT /
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2');
font-display: optional;
}

/ font-display: swap + size-adjust — good UX, minimal CLS /
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2');
font-display: swap;
}

/ Adjust fallback font to match custom font metrics /
@font-face {
font-family: 'MyFont-fallback';
src: local('Arial');
size-adjust: 105%;
ascent-override: 90%;
descent-override: 22%;
}

body { font-family: 'MyFont', 'MyFont-fallback', sans-serif; }

Why

font-display: optional tells the browser to use the fallback if the font is not in cache, eliminating FOUT entirely at the cost of occasionally showing the fallback. size-adjust closes the metric gap between the custom font and fallback, making the FOUT visually imperceptible.

Gotchas

  • Self-host fonts to avoid extra DNS lookups and connection overhead from Google Fonts CDN
  • Preload the woff2 font file with <link rel="preload" as="font" crossorigin> to reduce FOIT duration
  • font-display: block (browser default for @font-face) shows invisible text for up to 3 seconds — avoid it
  • Variable fonts reduce font file count and requests but may be larger than a single weight file

Code Snippets

Font Loading API with class-based fallback

// Use Font Loading API to detect when font is ready
document.fonts.load('1em MyFont').then(() => {
  document.documentElement.classList.add('fonts-loaded');
});

// CSS: apply font only after it is loaded
body { font-family: sans-serif; }
.fonts-loaded body { font-family: 'MyFont', sans-serif; }

Context

When custom fonts are causing visible text flashes or contributing to CLS score

Revisions (0)

No revisions yet.