Font Loading Strategy Guide

Complete guide to loading web fonts without hurting Core Web Vitals. Covers preload, font-display, fallback stacks, metric overrides, and browser behaviour for every strategy.

The three levers of font loading

Font loading performance is controlled by three CSS and HTML mechanisms. Getting any of them wrong silently degrades LCP or CLS:

  1. Preload — tells the browser to fetch the font in parallel with CSS, saving 100–500ms.
  2. font-display — controls what is shown before the font arrives (fallback vs invisible).
  3. Fallback stack — determines what users see if the font never loads or loads slowly.

Recommended pattern for most sites

<head>
  <link rel="preconnect" href="https://example.com">
  <link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
  <link rel="stylesheet" href="/css/main.css">
</head>
@font-face {
  font-family: "Main";
  src: url("/fonts/main.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

body {
  font-family: "Main", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

Preload rules

  • Preload only fonts used in the first rendered view — usually one font, occasionally two.
  • Always include crossorigin — fonts are fetched in CORS mode.
  • Include correct MIME type (type="font/woff2") so the browser deduplicates the request.
  • Place preload tags before any stylesheet link in <head>.
  • Do not preload Google Fonts URLs — the hashed URLs change, making stable preload impossible. Self-host instead.

font-display decision matrix

Content typeRecommended font-displayRationale
Body textswapReading must never be blocked
Headlines (LCP element)swapFallback renders instantly, swaps when font arrives
Hero image overlay textoptional or swap with adjusted fallbackZero CLS or fast enough swap
Icon fontsblockFallback glyphs render broken shapes
Decorative display fontsoptionalOK if slow-connection users never see them

Metric-adjusted fallbacks (advanced)

Fallback fonts have different metrics than your custom font, causing layout shift when the font swaps in. Modern CSS provides metric override properties that reduce this shift significantly:

@font-face {
  font-family: "Fallback";
  src: local("Arial");
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

body {
  font-family: "Main", "Fallback", sans-serif;
}

These properties adjust the fallback's rendering to match the primary font. The result: when the font swaps in, text barely shifts. This is the most effective technique for reducing CLS caused by late font swaps.

Self-host vs CDN

AspectSelf-hostGoogle Fonts CDN
DNS lookups1 (your domain)2 (fonts.googleapis.com + fonts.gstatic.com)
Preload supportYes — stable URLsDifficult — hashed URLs change
CachingYou control TTLGoogle controls TTL
GDPR complianceFull controlRequires consent in EU
Setup costHigherZero

Frequently asked questions

What is the fastest way to load web fonts?

One preloaded WOFF2 variable font (100–200KB), loaded via <link> in <head> with font-display: swap, plus a metric-adjusted fallback. Avoid @import entirely.

Should I self-host or use Google Fonts CDN?

Self-hosting is generally faster (one DNS lookup instead of two), enables stable preload URLs, and gives you GDPR compliance. Use CDN only for quick prototypes.

What is FOUT and why does it matter?

FOUT (Flash of Unstyled Text) means users briefly see fallback text before the custom font arrives. It is universally preferable to FOIT (Flash of Invisible Text) because it does not block reading.

How much does preload actually save?

Typical savings are 100–500ms of LCP improvement by fetching the font in parallel with CSS instead of after CSS parsing completes.

Can I preload all my fonts?

No. Preloading multiple fonts competes with other critical resources. Preload only the fonts used in the first rendered view.

Related tools