font-display: swap Explained
How to eliminate invisible text during web font loading and improve Core Web Vitals
Quick Answer
font-display: swap tells the browser to show text immediately using a fallback font, then swap to your custom font once it loads.
Add it to your @font-face rule:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap;
}What is font-display?
The font-display CSS property controls how a web font is displayed while it's loading. It's part of the @font-face rule.
When a browser encounters text styled with a web font that hasn't loaded yet, it must decide: should it show nothing (invisible text), show a fallback font, or wait? The font-display property gives you control over this behavior.
Without font-display, browsers default to making text invisible for up to 3 seconds while fonts load. This "Flash of Invisible Text" (FOIT) hurts user experience and Core Web Vitals scores.
All font-display values explained
auto
Browser decides. Usually behaves like block. Not recommended.
block
Short invisible period (~3s), then shows fallback indefinitely until font loads. Causes FOIT.
swap ← Recommended
Zero invisible period. Shows fallback immediately, swaps when font loads. Best for important text.
fallback
Very short invisible period (~100ms), then fallback. Only swaps if font loads quickly (~3s). Good balance.
optional
Very short invisible period (~100ms). Browser decides if it should use the font at all. Best for slow connections.
Why use font-display: swap?
Eliminates invisible text
Text is always visible, even on slow connections
Improves Largest Contentful Paint (LCP)
Critical text renders immediately, improving Core Web Vitals
Passes Lighthouse audits
Fixes "Ensure text remains visible during webfont load"
Better user experience
Users can read content immediately instead of waiting
How to implement font-display: swap
Self-hosted fonts
Add font-display: swap to your @font-face declarations:
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/inter-regular.woff2') format('woff2'),
url('/fonts/inter-regular.woff') format('woff');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/inter-bold.woff2') format('woff2'),
url('/fonts/inter-bold.woff') format('woff');
} Variable fonts
Same approach works for variable fonts:
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 100 900; /* Full weight range */
font-display: swap;
src: url('/fonts/Inter-Variable.woff2') format('woff2-variations');
}Using font-display with Google Fonts
Google Fonts supports font-display via the &display= parameter:
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet"> Pro tip: Self-host for best performance
While Google Fonts is convenient, self-hosting fonts gives you more control and eliminates third-party requests. Use Sift to download optimized, subsetted versions of any variable font.
swap vs optional: which should you use?
| Scenario | Recommendation |
|---|---|
| Brand/heading fonts | swap |
| Body text (long articles) | optional or fallback |
| Users on slow connections | optional |
| Layout shift is a concern | optional |
| Design consistency is critical | swap |
The tradeoff: swap guarantees your font appears but may cause a layout shift when it loads. optional prevents layout shift but may show the fallback font permanently on slow connections.
Fixing Lighthouse font warnings
If Lighthouse shows "Ensure text remains visible during webfont load", adding font-display: swap fixes it.
Complete fix checklist:
- Add
font-display: swapto all @font-face rules - If using Google Fonts, add
&display=swapparameter - Preload critical fonts with
<link rel="preload"> - Subset fonts to reduce file size and load time
Preloading fonts
Combine font-display with preloading for best results:
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>Best practices
1. Use WOFF2 format
WOFF2 offers 30% better compression than WOFF. Faster downloads mean faster swaps.
2. Subset your fonts
Remove unused characters to dramatically reduce file size. A full Inter font is 387KB; subsetted for Latin can be under 20KB.
3. Choose similar fallback fonts
Pick a system font with similar metrics to minimize layout shift when swapping.
4. Use font-display per use case
It's okay to use swap for headings and optional for body text in the same project.
Optimize your fonts with Sift
Sift generates optimized, subsetted WOFF2 fonts with font-display: swap CSS snippets ready to copy. Reduce font file sizes by 70% or more.
Frequently Asked Questions
What does font-display: swap do? ▼
font-display: swap tells the browser to immediately show text using a fallback font while the custom web font loads in the background. Once loaded, the browser swaps to the custom font. This eliminates the "flash of invisible text" (FOIT) that occurs when fonts load slowly.Does font-display: swap affect Core Web Vitals? ▼
font-display: swap improves Largest Contentful Paint (LCP) by ensuring text is visible immediately. It also helps pass the Lighthouse "Ensure text remains visible during webfont load" audit.What are all the font-display values? ▼
font-display property accepts five values: auto (browser default), block (brief invisible period), swap (immediate fallback, then swap), fallback (short invisible period, may not swap if slow), and optional (very short invisible period, browser chooses whether to use font).Should I use font-display: swap or optional? ▼
swap for brand fonts where design consistency matters. Use optional for body text where preventing layout shift is more important than using the exact font. optional is better for users on slow connections.Does font-display work in all browsers? ▼
font-display has excellent browser support. It works in Chrome 60+, Firefox 58+, Safari 11.1+, Edge 79+, and all modern mobile browsers. Browsers that don't support it simply ignore it.