Skip to content
intermediatePhase 38 · Web Performance

Font Optimization

Load web fonts efficiently with font-display, subsetting, and preload.

30m
0 problems
Topic Progress0%

font-display

font-display

Control how fonts load and display.

font-display Values

/* Swap: Show fallback immediately, swap when ready */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: swap;
}

/* Fallback: Show fallback, swap only if ready quickly */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: fallback;
}

/* Block: Hide text for up to 3 seconds */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: block;
}

/* Optional: Show fallback only */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: optional;
}

Recommended Usage

Use Case font-display
Body text swap
Headings swap or fallback
Icons block
Critical UI optional

Implementation

/* Google Fonts example */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');

/* Self-hosted */
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF; /* Latin characters only */
}

Font Subsetting

Font Subsetting

Include only the characters you need to reduce file size.

Unicode Range

/* Latin characters */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom-latin.woff2') format('woff2');
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F;
}

/* Greek characters */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom-greek.woff2') format('woff2');
  font-display: swap;
  unicode-range: U+0370-03FF;
}

/* Cyrillic characters */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom-cyrillic.woff2') format('woff2');
  font-display: swap;
  unicode-range: U+0400-04FF;
}

Generate Subsets

# Using pyftsubset
pip install fonttools brotli
pyftsubset input.ttf \
  --output-file=output-latin.woff2 \
  --flavor=woff2 \
  --unicodes=U+0000-00FF

# Using Google Fonts API
https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap

Variable Fonts

/* Single file for all weights */
@font-face {
  font-family: 'InterVariable';
  src: url('/fonts/inter-variable.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-display: swap;
}

/* Use variable weights */
body {
  font-family: 'InterVariable';
  font-weight: 400;
}

h1 {
  font-weight: 700;
}

Size Comparison

Format Full Font Latin Subset Reduction
TTF 500KB 150KB 70%
WOFF2 300KB 90KB 70%
Variable 200KB 60KB 70%

Font Preloading

Font Preloading

Preload critical fonts to prevent FOUT/FOIT.

HTML Preload

<!-- In <head> -->
<link
  rel="preload"
  href="/fonts/inter-400.woff2"
  as="font"
  type="font/woff2"
  crossorigin
/>
<link
  rel="preload"
  href="/fonts/inter-700.woff2"
  as="font"
  type="font/woff2"
  crossorigin
/>

JavaScript Preloading

// Preload fonts
document.fonts.preload('/fonts/inter-400.woff2');
document.fonts.preload('/fonts/inter-700.woff2');

// Wait for fonts to load
await document.fonts.ready;
console.log('Fonts loaded');

Size-Adjust for Fallback

/* Match fallback font metrics to minimize CLS */
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter.woff2') format('woff2');
  font-display: swap;
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

/* Fallback font stack */
:root {
  --font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

Critical Font Loading Strategy

<!-- Inline critical font CSS -->
<style>
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-400.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
  unicode-range: U+0000-00FF;
}
</style>

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

<!-- Load non-critical fonts async -->
<script>
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = '/fonts.css';
document.head.appendChild(link);
</script>

Font Loading Checklist

  • Use font-display: swap or fallback
  • Preload critical fonts
  • Subset fonts for needed characters
  • Use variable fonts when possible
  • Match fallback font metrics
  • Limit font weights (2-3 max)
  • Self-host fonts for better caching

Practice Problems

0/3solved
Build Font Optimization Component

Create a reusable React component implementing Font Optimization. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
Font Optimization Testing

Write unit and integration tests for Font Optimization using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
Font Optimization Performance

Optimize Font Optimization for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What does font-display: swap do?

Question 1 options

2. What is font subsetting?

Question 2 options

3. Why preload fonts?

Question 3 options

4. What is the benefit of variable fonts?

Question 4 options

5. What is size-adjust?

Question 5 options

Flashcards

Question

What are the font-display values?

Answer

auto, block, swap, fallback, optional - each controls how fonts load and display.

Question

What is font subsetting?

Answer

Including only the characters needed to reduce font file size.

Question

Why use variable fonts?

Answer

Single file for all weights/styles, reducing HTTP requests and total file size.

Question

What is size-adjust?

Answer

A CSS property that adjusts fallback font metrics to match the custom font, reducing CLS.

Question

What is Font Optimization?

Answer

Font Optimization is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.font-display: swap is best for most use cases
  • 2.Font subsetting can reduce file size by 70%+
  • 3.Variable fonts provide all weights in one file
  • 4.Preload critical fonts to prevent FOUT/FOIT
  • 5.Match fallback metrics to reduce CLS

Interview Tips

  • Explain the difference between font-display values
  • Discuss font subsetting and when to use it
  • Know how to prevent CLS from font loading

Cheat Sheet

Font Optimization Cheat Sheet

font-display

  • swap: Show fallback, swap when ready
  • fallback: Show fallback, swap if quick
  • block: Hide text up to 3s
  • optional: Show fallback only

Subsetting

  • Use unicode-range for character subsets
  • Variable fonts for all weights in one file

Preloading

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

CLS Prevention

  • Match fallback metrics with size-adjust
  • Use font-display: swap
  • Preload critical fonts