Script Valley
Web Performance Fundamentals
Image and Font OptimizationLesson 3.4

How to load web fonts without causing layout shift or FOIT

FOIT, FOUT, font-display values, font preloading, unicode-range subsetting, variable fonts, Google Fonts optimization, system font stack fallback

Optimizing Web Font Loading

FOIT (Flash of Invisible Text) and FOUT (Flash of Unstyled Text) both degrade perceived performance. font-display controls the tradeoff.

@font-face {
  font-family: 'Geist';
  src: url('/fonts/geist.woff2') format('woff2');
  font-weight: 100 900; /* variable font range */
  font-display: swap;   /* show fallback immediately, swap when loaded */
  unicode-range: U+0000-00FF; /* Latin only — skip loading for other scripts */
}

font-display values:

  • swap — fallback immediately, swap when font loads (FOUT, no invisible text)

  • optional — if font doesn't load in ~100ms, use fallback forever (no swap, zero CLS risk)

  • block — invisible text for up to 3s (FOIT, avoid for body text)

Preload critical fonts to eliminate the discovery delay:

<link rel="preload" as="font" type="font/woff2"
  href="/fonts/geist.woff2" crossorigin>

If using Google Fonts, append &display=swap to the URL and self-host the files for privacy and performance (eliminates third-party DNS + TCP). Use the google-webfonts-helper tool to download optimized WOFF2 subsets. Variable fonts serve all weights from a single file, halving the number of font requests.

Up next

How to compress and optimize images at build time with Sharp and Squoosh

Sign in to track progress