🔄

Font Loading Strategies

FOIT vs FOUT, font-display values, and the Font Loading API. Choose the right strategy for optimal performance and user experience.

📖 10 min read Last updated: January 2025

Quick Answer

Use font-display: swap for most websites. It shows fallback text immediately (avoiding FOIT) and swaps to your custom font when loaded. For performance-critical pages where you'd rather skip fonts than cause layout shift, use font-display: optional.

FOIT vs FOUT Explained

When a browser downloads a web font, it needs to decide what to show while waiting. This creates two fundamental behaviors that have different impacts on user experience:

FOIT

Flash of Invisible Text

  • • Text is hidden while font loads
  • • Users see blank space
  • • Content is unreadable during load
  • • Hurts Largest Contentful Paint (LCP)
  • • Default in older browsers
👻

Invisible until loaded

FOUT

Flash of Unstyled Text

  • • Text shows in fallback font
  • • Content is always readable
  • • Swaps when custom font loads
  • • Better for Core Web Vitals
  • • Preferred modern approach
📖

Readable immediately

Bottom line: FOUT is almost always better than FOIT. Users can read your content immediately, which improves both user experience and Core Web Vitals scores.

The font-display Property

The font-display CSS property controls how fonts are displayed during loading. Add it to your @font-face rules:

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;  /* The key property */
}

font-display Values

swap Recommended

Shows fallback text immediately. Swaps to custom font when loaded, regardless of how long it takes.

Use when: You want text always visible and accept the swap.

block

Hides text for up to 3 seconds (block period). Then shows fallback and swaps when loaded.

Use when: Only for icon fonts where invisible icons are acceptable briefly.

fallback

Very short block period (~100ms), then fallback. Only swaps if font loads within ~3 seconds.

Use when: You want minimal FOIT and can accept the font might not load on slow connections.

optional Performance-first

Uses font only if already cached. No block period, no swap. Falls back permanently if not instant.

Use when: Performance is critical and you'd rather skip custom fonts than cause any visual disruption.

auto

Browser decides. Usually behaves like block. Avoid—be explicit.

Use when: Never. Always specify a value explicitly.

Strategy Comparison

StrategyFOITFOUTLCPCLS Risk
font-display: swap
NoYesGoodSome risk
font-display: block
Yes (short)YesPoorSome risk
font-display: fallback
MinimalMaybeGoodReduced
font-display: optional
NoNoBestNone
Font Loading API
ConfigurableConfigurableConfigurableConfigurable

Font Loading API

The Font Loading API (document.fonts) provides JavaScript control over font loading. Use it for advanced scenarios.

Detect When Fonts Load

// Wait for all fonts to load
document.fonts.ready.then(() => {
  console.log('All fonts loaded!');
  document.body.classList.add('fonts-loaded');
});

// Check if a specific font is loaded
document.fonts.check('16px Inter'); // true/false

// Wait for a specific font
document.fonts.load('400 16px Inter').then(() => {
  console.log('Inter loaded!');
});

FOUT with a Class Pattern

A popular pattern: hide custom fonts until loaded, then add a class to enable them:

/* CSS: Use fallback by default */
body {
  font-family: system-ui, sans-serif;
}

/* When fonts are loaded, use custom font */
.fonts-loaded body {
  font-family: 'Inter', system-ui, sans-serif;
}
// JavaScript: Add class when fonts load
if (document.fonts) {
  document.fonts.ready.then(() => {
    document.documentElement.classList.add('fonts-loaded');
  });
} else {
  // Fallback for older browsers
  document.documentElement.classList.add('fonts-loaded');
}

Browser Support: The Font Loading API is supported in all modern browsers (96%+ global support). For older browsers, use a fallback that assumes fonts are loaded.

Modern Loading Approaches

1. Simple: font-display: swap + Preload

Best for most websites. Combine font-display: swap with preloading critical fonts:

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

2. Performance-First: font-display: optional

For maximum performance. First visit uses system fonts; subsequent visits use cached custom fonts. Zero CLS.

Great for: Landing pages, e-commerce, any site where speed > brand consistency

3. Critical Font Strategy

Different strategies for different fonts based on importance:

  • Body text: font-display: swap + preload
  • Headings: font-display: swap
  • Decorative: font-display: optional
  • Icon fonts: font-display: block

4. Minimize CLS with Font Matching

Reduce layout shift by matching your fallback font's metrics to your custom font:

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter.woff2') format('woff2');
  font-display: swap;
  /* Adjust fallback metrics */
  size-adjust: 100%;
  ascent-override: 90%;
  descent-override: 20%;
}

Tools like Fallback Font Generator can calculate these values.

Recommendations by Use Case

Most Websites

  • Use font-display: swap
  • Preload 1-2 critical fonts
  • Subset fonts to reduce file size
  • Use WOFF2 format

E-commerce / Landing Pages

  • Consider font-display: optional for zero CLS
  • System fonts on first visit is acceptable
  • Custom fonts load from cache on return visits

Brand-Heavy Sites

  • Use font-display: swap
  • Always preload critical fonts
  • Use Font Loading API for controlled transitions
  • Match fallback font metrics to minimize CLS

Icon Fonts

  • Use font-display: block
  • Brief invisibility is better than showing wrong characters
  • Consider switching to SVG icons for better performance

Frequently Asked Questions

What is FOIT in web fonts?

FOIT (Flash of Invisible Text) is when text is hidden while a web font loads. Users see blank space until the font downloads. This hurts user experience and Core Web Vitals, especially Largest Contentful Paint.

What is FOUT in web fonts?

FOUT (Flash of Unstyled Text) is when browsers show a fallback font while the custom font loads, then swap when ready. Content is always readable, but there's a visual "flash" during the swap.

Which font-display value should I use?

Use font-display: swap for most sites—it shows fallback text immediately. Use font-display: optional for performance-critical pages where avoiding visual disruption matters more than custom fonts on first load.

How does font-display: optional work?

With optional, the browser uses the custom font only if it's already cached. First-time visitors see system fonts. On subsequent visits, they see your custom font with zero loading delay and zero layout shift.

Does font-display cause layout shift (CLS)?

swap and fallback can cause CLS when fonts load and text reflows. optional causes zero CLS. You can minimize CLS with any strategy by matching fallback font metrics.

Related Guides

Optimize Your Fonts Now

Upload any font and get an optimized WOFF2 with proper CSS output including font-display recommendations.

Try Sift Free