Font Optimization Guide
Complete guide to reducing web font payload and improving Core Web Vitals. WOFF2 conversion, subsetting, variable fonts, preloading, and the specific metrics you can expect from each step.
Font optimization checklist
Cache-Control: public, max-age=31536000, immutable.Step 1 — Convert to WOFF2
WOFF2 uses Brotli compression and produces the smallest usable font files. Every modern browser (Chrome 36+, Firefox 39+, Safari 12+, Edge 14+) supports it.
| Source format | Typical WOFF2 size | Reduction |
|---|---|---|
| TTF | 25–35% of original | 65–75% |
| OTF | 25–35% of original | 65–75% |
| WOFF | 60–75% of original | 25–40% |
Convert with the TTF to WOFF2 Converter, OTF to WOFF2 Converter, or WOFF to WOFF2 Converter.
Step 2 — Subset to the glyphs you actually use
Most fonts ship with support for multiple scripts — Latin, Cyrillic, Greek, Devanagari, Arabic, CJK. If your site only targets English readers, you are downloading 40–70% of unused glyphs.
Two approaches:
- Manual subsetting with fonttools — run
pyftsubseton your font file with the exact characters or Unicode ranges you need:
pyftsubset Inter.ttf \
--unicodes="U+0020-007E" \
--flavor=woff2 \
--output-file=Inter-Latin.woff2
- Unicode-range subsetting in CSS — serve multiple subsets with
unicode-rangedeclarations. The browser downloads only the subset that matches the characters actually used on the page:
@font-face {
font-family: "Inter";
src: url("/fonts/inter-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153;
}
Step 3 — Prefer variable fonts
A static font family typically ships as separate files for each weight: 100, 300, 400, 500, 700, 900. That is six files, six network requests, and roughly 900KB total for a font like Inter.
A variable font replaces all of these with one WOFF2 file of around 100–200KB. The CSS declares a weight range:
@font-face {
font-family: "Inter";
src: url("/fonts/inter-var.woff2") format("woff2");
font-weight: 100 900;
}
The tradeoff: variable font files are larger than a single static weight, but smaller than the total of multiple weights. If you only use one weight, a single static file may be smaller. Use a variable font when you need 2+ weights.
Step 4 — Preload and font-display
See the Font Loading Strategy Guide for the complete walkthrough of preload, font-display, and metric-adjusted fallbacks.
Step 5 — Cache aggressively
Fonts are static assets. Once a version is deployed, it never changes. Serve them with:
Cache-Control: public, max-age=31536000, immutable
When you update the font, use a new filename (or a query string like ?v=2). The new file gets a fresh cache entry; the old file is cached forever, which is fine.
On Cloudflare Pages, this is configured in _headers:
/assets/fonts/*
Cache-Control: public, max-age=31536000, immutable
Measuring the impact
After applying these optimizations, measure the improvement using real-user data in Google Search Console's Core Web Vitals report — not just Lighthouse lab scores. The metric to track is LCP (Largest Contentful Paint), which is typically the headline text using your font.
Typical improvement from optimizing a poorly-loaded web font:
| Optimization | Typical LCP improvement | Typical byte savings |
|---|---|---|
| TTF to WOFF2 conversion | 200–500ms | 60–75% |
| Subsetting | 100–300ms | 40–70% |
| Variable font (vs multiple static) | 300–800ms | 60–80% |
| Preload with crossorigin | 100–400ms | 0 |
| font-display: swap | Eliminates invisible-text LCP delay | 0 |
Frequently asked questions
What is the fastest web font format?
WOFF2 uses Brotli compression and produces the smallest usable files. It is supported by every modern browser and reduces file size by 30% versus WOFF and 65% versus TTF/OTF.
What is font subsetting?
Removing unused glyphs from a font file. If your site only needs Basic Latin, you can strip Cyrillic, Greek, and CJK glyphs, often reducing file size by 40–70%. Use fonttools pyftsubset or a subsetting service.
Are variable fonts smaller than static fonts?
One variable font file is smaller than 4+ static files combined. A variable font covering 100–900 weight in WOFF2 is typically 100–200KB. The equivalent 9 static WOFF2 files total 700–1500KB.
Is font subsetting legal?
It depends on the license. SIL OFL 1.1 explicitly permits subsetting as long as you do not use the Reserved Font Name (if one is declared). Apache 2.0 also permits subsetting. Commercial licenses often restrict modification — check before subsetting.
What is a good font file size for web?
Under 100KB per WOFF2 file is good. Under 50KB is excellent. Anything over 200KB should be subsetted further or replaced with a lighter alternative.