Web Performance By FlyFish NWA Editorial, Cloud Infrastructure Specialist • • 7 min read

CDN Font Loading Strategy: FOUT, FOIT, and Optimal Font Delivery

Web fonts are a top cause of layout shift and invisible text. Learn how to use CDN caching, font-display, preload, and subsetting to deliver fonts fast without FOIT or jarring FOUT.

ER
Emma Rodriguez
Cloud Infrastructure Specialist • CDN & Edge Performance

Custom web fonts define brand identity, but they are also render-blocking. If delivered naively from origin, fonts create two infamous user experiences: FOIT (Flash of Invisible Text) and FOUT (Flash of Unstyled Text). When you serve fonts through a CDN, you have the infrastructure to eliminate both — if you configure caching, headers, and CSS correctly.

This guide breaks down the tradeoffs between FOUT and FOIT, how font-display controls the browser timeline, and the exact CDN delivery pattern that minimizes Cumulative Layout Shift (CLS) and Largest Contentful Paint (LCP) impact.

FOIT vs. FOUT: What Actually Happens

Browsers need text to render before fonts arrive. What they do in that gap defines the experience:

  • FOIT: Browser hides text (invisible) for up to 3 seconds while waiting for the web font. If the font fails or is slow, users see nothing. Great for avoiding layout shift, terrible for perceived performance and accessibility.
  • FOUT: Browser shows fallback system font immediately, then swaps to the web font when it loads. Content is instantly readable, but you get a visible reflow and style jump.

Neither is ideal by default. The goal is a controlled swap — instant readable text with minimal visual shift — achieved through CDN-optimized delivery and proper font-display.

The font-display Spectrum

font-display inside @font-face tells the browser how long to block and how long to swap. Your CDN cannot fix a bad font-display choice — cache hits will still trigger FOIT if you use block.

Performance Comparison: Edge vs Origin Processing
Metric Edge Processing Origin Processing Improvement
Latency (p50)8–15 ms120–300 ms15–20x faster
Cache Hit Ratio85–95%N/AReduces origin load
TLS Handshake1–5 ms (nearby PoP)50–150 ms10–30x faster
Bandwidth Cost$0.01–0.04/GB$0.05–0.12/GB3–5x cheaper
Availability99.99% (multi-PoP)99.9% (single DC)10x fewer outages
font-display Block Period Swap Period Best For
block FOIT risk 3s invisible Infinite Logo / icon fonts where fallback is unacceptable
swap Recommended ~100ms Infinite Body text, headings — instant readability
fallback ~100ms ~3s Secondary fonts where brief FOUT is okay
optional Fastest ~100ms None Performance-critical pages; uses cache or fallback only
auto Browser default (usually block) Varies Avoid — unpredictable across browsers

For most content sites, font-display: swap is the optimal default, combined with a well-matched fallback to reduce CLS. For hero text where layout shift is costly, pair swap with size-adjust and CDN preloading. optional is powerful for repeat visits — if the font is already in the CDN edge cache and HTTP cache, it swaps; otherwise it avoids a late swap entirely.

Learn how edge delivery affects overall metrics in our overview of CDN benefits for performance and security.

Optimal CDN Font Delivery: 5 Layers

1. Serve from Edge with Long-Lived, Immutable Caching

Fonts are ideal for aggressive caching — they are versioned and immutable. Serve WOFF2 only (30% smaller than WOFF) and fingerprint filenames like inter-v12-latin-400.woff2.

Set these headers at origin and propagate to the CDN:

# Nginx / CloudFront / Cloudflare Worker origin headers
Cache-Control: public, max-age=31536000, immutable
Access-Control-Allow-Origin: * # Required for cross-origin fonts
Content-Type: font/woff2
Timing-Allow-Origin: *

On the CDN, enable Origin Shield and Tiered Cache so a single origin fetch populates all edges. This is especially important for fonts because a cache miss during LCP is far more damaging than for an image. For cost planning, see CDN cost optimization to balance long TTLs with purge strategies.

2. Preload Critical Fonts (Only 1-2 Files)

Preload eliminates the discovery delay — without it, the browser only discovers fonts after CSS is parsed. Preload from the same CDN hostname as your CSS to reuse the connection.

<!-- In <head> — must match @font-face URL exactly -->
<link rel="preload" href="https://cdn.flyfishnwa.com/fonts/inter-v12-latin-400.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="https://cdn.flyfishnwa.com/fonts/inter-v12-latin-700.woff2" as="font" type="font/woff2" crossorigin>

/* Preconnect to CDN if fonts are on separate domain */
<link rel="preconnect" href="https://cdn.flyfishnwa.com" crossorigin>
Rule: Preload only above-the-fold fonts (usually 400 regular + 700 bold). Preloading 4+ variants competes with LCP image and defeats the purpose. Audit with Lighthouse — if a preloaded font isn’t used in 3s, it’s wasted.

3. Use @font-face with swap and size-adjust

Reduce CLS by matching fallback metrics to your web font. Modern CSS lets you adjust fallback size, ascent, and line gap:

@font-face {
  font-family: 'Inter';
  src: url('https://cdn.flyfishnwa.com/fonts/inter-v12-latin-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC;
}

/* Metric-matched fallback to minimize CLS */
@font-face {
  font-family: 'Inter-fallback';
  src: local("Arial");
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

body {
  font-family: 'Inter', 'Inter-fallback', system-ui, sans-serif;
}

Generate overrides with tools like Fontpie or Capsize. A well-tuned fallback can cut CLS from 0.15 to <0.02 even with swap.

4. Subset and Self-Host — Don’t Proxy Google Fonts

Self-hosting on your CDN outperforms proxying Google Fonts for three reasons: you control caching headers, you avoid an extra connection to fonts.googleapis.com, and you can subset aggressively.

  • Subset by language: latin vs latin-ext can save 60-80KB per weight.
  • Use unicode-range to let the browser download only needed subsets.
  • Convert to WOFF2 only; drop EOT/TTF.

If you must use a third-party font service, use CDN edge computing to cache the CSS response at the edge and rewrite it to your domain.

5. Fix CORS and Compression

Fonts fail silently with CORS errors. Your CDN must return:

Access-Control-Allow-Origin: *
Cross-Origin-Resource-Policy: cross-origin

Enable Brotli (level 11) at the edge — WOFF2 is already compressed, but font CSS benefits. Ensure HTTP/2 or HTTP/3 is enabled so preloaded fonts multiplex without head-of-line blocking. For high-traffic sites, pair this with smart routing via CDN load balancing algorithms to keep edge latency <20ms.

Measuring Success

Validate your strategy with field and lab data:

  • Lighthouse / PageSpeed: Watch “Ensure text remains visible during webfont load” and CLS. Preload should remove that audit warning.
  • WebPageTest: Filmstrip should show text at ~0.8s, not 2.5s. Check waterfall — font should start at high priority before CSS finishes.
  • CrUX / RUM: Track CLS and LCP by font cache hit rate. A CDN with 98%+ edge hit rate typically improves LCP by 200-400ms vs origin.

For e-commerce where font-induced CLS directly hurts conversion, apply the same edge priority logic described in CDN for e-commerce.

Common Pitfalls to Avoid

  • Preloading with wrong crossorigin: Missing crossorigin causes double download — browser fetches preload anonymously but needs CORS for font.
  • @import for fonts: Blocks CSS parsing. Always use <link> or inline @font-face in critical CSS.
  • No font-display: Defaults to block (FOIT). Explicitly set swap or optional.
  • Cache-Control: no-store: Some origins send this for fonts — override at CDN edge or fix origin.
  • Over-subsetting: Removing characters needed for user-generated content causes tofu (□) glyphs. Test with real content.

When fonts are delivered correctly from the edge — immutable, preloaded, swapped with metric-matched fallbacks — users get instant readable text and a stable layout. That’s the difference between a CDN that merely hosts fonts and one that optimizes reading experience.

Frequently Asked Questions

Should I use font-display: swap or optional for CDN-hosted fonts?

Use swap for body and heading fonts where brand consistency matters — it guarantees the web font appears after ~100ms. Use optional for non-critical weights (e.g., 300 light, 800 extra-bold) or on performance-critical landing pages where you prefer no late swap if the font isn’t cached. Optional relies heavily on CDN and HTTP cache hits.

How many fonts should I preload from the CDN?

Preload at most 2 WOFF2 files — typically regular (400) and bold (700) for above-the-fold text. Each preload is high-priority and competes with your LCP image. Preloading more than 2 often harms performance. Let the browser fetch remaining weights normally via font-display: swap.

Why is my CDN font not loading due to CORS?

Browsers require CORS for fonts. Your CDN must return Access-Control-Allow-Origin: * (or your exact origin) and serve fonts with crossorigin requests. Ensure your <link rel="preload" as="font" crossorigin> includes the crossorigin attribute and that the CDN forwards the Origin header and caches separate CORS variants.

Does self-hosting fonts on a CDN outperform Google Fonts?

Yes, for performance. Self-hosting eliminates an extra DNS/TCP/TLS connection to fonts.googleapis.com, gives you full control over Cache-Control: immutable and Brotli, and allows aggressive subsetting and unicode-range. Google Fonts is convenient, but self-hosted WOFF2 on your own CDN edge typically saves 100-300ms on first visit.

References & Standards: Cloudflare documentation · OWASP CDN Security