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.
