⚡IntermediatePerformance and Loading
Font Loading Optimization
Eliminate flash of invisible/unstyled text with font-display, preload, and self-hosted fonts.
Overview
Web fonts are one of the most common sources of layout shift and rendering delay. When a browser downloads a custom font, it may show invisible text (FOIT Flash of Invisible Text) or swap in the system font first then the web font (FOUT Flash of Unstyled Text).
Optimization techniques:
1. font-display: swap shows fallback font immediately, swaps when custom font loads
2. Preload the font file fetches it earlier in the loading process
3. Self-host fonts avoids third-party DNS round trips
4. Use variable fonts one file covers all weights/styles
5. Subset fonts only include the characters your language needs
6. WOFF2 format ~30% smaller than WOFF
Key Points
- •font-display: swap shows fallback immediately, then swaps minimizes FOIT
- •font-display: optional only uses font if already cached best for subtle fonts
- •Preloading the woff2 font file reduces the download latency significantly
- •Self-hosting avoids third-party DNS resolution (faster than Google Fonts CDN for most users)
- •System font stack (font-family: system-ui) zero network request, instant rendering
- •Subsetting: only ship characters for the language (latin-ext vs all unicode)
Examples
Self-hosted font with font-display: swap
<!-- In <head>: preload the font before CSS discovers it -->
<link rel="preload" href="/fonts/inter-var.woff2"
as="font" type="font/woff2" crossorigin>
<!-- In CSS or <style> -->
<style>
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-var.woff2') format('woff2');
font-weight: 100 900; /* Variable font range */
font-display: swap; /* Show fallback immediately */
font-style: normal;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont,
'Segoe UI', sans-serif;
}
</style>Google Fonts with display=swap
<!-- Preconnect to Google Fonts origins -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Load font with display=swap parameter -->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap">display=swap in the Google Fonts URL sets font-display:swap on the generated @font-face.
font-display values comparison
/* auto: browser default (usually block) */
font-display: auto;
/* block: invisible text for up to 3s, then swap */
font-display: block;
/* swap: show fallback immediately, swap when loaded */
font-display: swap;
/* fallback: 100ms block, then fallback; swap within 3s */
font-display: fallback;
/* optional: 100ms block, only use if cached */
font-display: optional;swap is best for most text; optional is best for decorative/non-critical fonts.
Common Mistakes
- Not adding crossorigin to font preload the preload is ignored silently
- Using font-display: block for body fonts shows invisible text for up to 3 seconds
- Preloading all font weights only preload the weight loaded immediately on the page
Note
The fastest font is a system font. Before adding a custom font, consider: is the visual difference worth 40-200KB of network overhead? Many high-performance sites use system fonts (GitHub, Wikipedia, Notion initially).
Exercises
Write HTML to solve each exercise. Use Preview to see it render in a live iframe, then mark as done.
Loading editor…
Completed: 0 / 5 exercises
Knowledge Check
Question 1 of 4