What is Font Subsetting?
Font subsetting is the process of removing unused characters from a font file, keeping only the glyphs your website actually needs. A typical web font like Roboto contains thousands of characters for multiple languages, but your site probably only uses a fraction of them.
When you subset a font to just the Latin characters you need, file sizes drop dramatically. Research shows Roboto Regular weighing 168KB as a TTF can be reduced to just 12KB as a subsetted WOFF2 file — a 93% reduction. Inter, a variable font, drops from 303KB to 22KB (93% reduction) with Latin-only subsetting.
Common Misconception
Unicode-range doesn't subset your font files. The unicode-range CSS descriptor controls which font files the browser downloads, but it doesn't actually reduce the file size. If your page contains any character in the range, the entire font file downloads with all its glyphs. The correct approach is to use both: physically subset the files, then use unicode-range to tell the browser which subset to load.
Character Sets and Scripts
Fonts are organized by character sets and scripts. Understanding these helps you choose what to include:
- Basic Latin — English letters, numbers, basic punctuation (typically 12-30KB)
- Latin Extended — Additional European characters, accented letters (adds 5-15KB)
- Cyrillic — Russian, Bulgarian, Serbian (adds 5-15KB)
- Greek — Greek alphabet (adds 5-15KB)
- CJK — Chinese, Japanese, Korean (adds megabytes — avoid unless needed)
When to Subset
Subsetting makes sense when you know exactly which characters appear on your site. It's ideal for:
- Landing pages with controlled text
- Marketing sites with predictable content
- Apps with limited character requirements
Avoid subsetting for user-generated content sites, forums, or anywhere users might type in multiple languages.
Unicode-Range Optimization
The unicode-range CSS property lets browsers download only the font characters they need, even from a full font file. It's like progressive loading for fonts.
How Unicode-Range Works
Instead of subsetting upfront, you serve a full font but tell the browser which codepoints it covers. The browser checks what characters are on the page and only downloads the matching portions:
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2');
unicode-range: U+0020-007F, U+00A0-00FF;
}This example covers Basic Latin (U+0020-007F) and Latin Extended-A (U+00A0-00FF). The browser sees this range and only downloads glyphs for those characters.
Common Unicode Ranges
U+0020-007F— Basic Latin (English)U+00A0-00FF— Latin-1 SupplementU+0100-017F— Latin Extended-BU+0400-04FF— CyrillicU+0370-03FF— Greek
Combining Subsetting with Unicode-Range
The most effective approach combines both techniques: subset your fonts for your primary languages, then use unicode-range to handle fallback gracefully. This gives you minimal file sizes with intelligent browser fetching.
Variable Fonts
Variable fonts pack multiple font variations (weights, widths, styles) into a single file. Instead of loading separate files for Regular, Medium, Bold, and Black, you load one file and specify properties like font-weight: 500 or font-stretch: 75%.
Break-Even Analysis
Variable fonts aren't always smaller. The break-even point is typically around 3 weights. Here's the math:
| Weights Used | Static Files Total | Variable Font | Winner |
|---|---|---|---|
| 1-2 weights | 20-40KB | 60-80KB | Static |
| 3 weights | 60-120KB | 60-80KB | Variable |
| 5+ weights | 100-200KB+ | 60-80KB | Variable |
Subsetting Variable Fonts
Subsetting variable fonts requires extra care. Using fonttools subset, you need to specify which axes to keep:
fonttools subset font.woff2 \
--text="Hello World" \
--output-file=subset.woff2 \
--layout-features='*' \
--flavor=woff2When Variable Fonts Make Sense
Use variable fonts when you need fine-grained typographic control — multiple weights, widths, optical sizes, or slants. They're especially powerful for design systems where you want consistent typography across many components without managing dozens of font files.
Font Loading Strategies
Even optimized fonts can block page rendering. The font-display CSS property controls how browsers handle font loading, determining the trade-off between perceived load speed and visual stability.
Font-Display Values
| Value | Behavior | Best For |
|---|---|---|
swap | Show fallback immediately, swap when loaded | Most websites (recommended) |
block | Invisible text until font loads (FOIT) | When text must match exactly |
fallback | Very short block, then fallback | Balanced approach |
optional | Browser decides (network-dependent) | Performance-first sites |
Recommended: font-display: swap
Use font-display: swap for most cases. Users see fallback text immediately (preventing invisible text), then the custom font swaps in once loaded. This is the best balance of perceived performance and user experience.
Preloading Critical Fonts
For above-the-fold text, consider preloading to eliminate layout shift:
<link rel="preload"
href="/fonts/myfont.woff2"
as="font"
type="font/woff2"
crossorigin>Only preload fonts that are immediately visible. Preloading too many fonts delays other critical resources.
Self-Hosting vs Google Fonts
Both self-hosting and Google Fonts have merits. The right choice depends on your site's traffic patterns, update frequency, and performance requirements.
Self-Hosting Benefits
- Full control — Subset, compress, and optimize exactly as needed
- No third-party requests — Eliminates DNS lookups and connection setup
- Better cache behavior — Long-term caching with your version control
- Privacy — No requests to Google servers
When Google Fonts Makes Sense
- Rapid prototyping — Quick iteration without build steps
- Large font libraries — Access to 1,400+ families easily
- Automatic updates — Fonts stay current without manual work
- Simple sites — Blogs or landing pages with minimal customization
Google Fonts with Self-Hosting
A hybrid approach works well: download Google Fonts and self-host the subsetted versions. You get the selection convenience with the performance benefits of self-hosting.
Real-World Benchmarks
Here's what actual font optimization looks like in practice, using common open-source fonts:
| Font | Original (TTF) | WOFF2 | Latin Subset | Total Savings |
|---|---|---|---|---|
| Roboto Regular | 168KB | 53KB (68%) | 12KB | 93% |
| Open Sans | 215KB | 68KB (68%) | 18KB | 92% |
| Inter | 303KB | 95KB (69%) | 22KB | 93% |
These savings add up quickly across a site. To convert your fonts to WOFF2 for the best compression, use our TTF to WOFF2 converter or OTF to WOFF2 converter.
Tools for Measuring
- Lighthouse — Core Web Vitals, including font load performance
- WebPageTest — Waterfall charts showing font download timing
- Chrome DevTools — Network tab with font file sizes
- FontTools — CLI for subsetting (pip install fonttools)
Licensing Considerations
Not all fonts can be legally subset. Many commercial licenses prohibit modification of the font file, including subsetting. The SIL Open Font License (OFL) permits subsetting but treats the result as a "Modified Version" — if the font has a Reserved Font Name, subsets must be renamed. Always check the EULA before subsetting.
Frequently Asked Questions
Does font subsetting affect quality?
No. Subsetting only removes glyphs — it doesn't alter the remaining characters. The font renders identically; it simply contains fewer characters. There's no quality loss.
How much smaller are WOFF2 fonts compared to TTF?
WOFF2 uses Brotli compression, achieving 60-70% smaller files compared to uncompressed TTF. A 168KB Roboto TTF becomes 53KB as WOFF2. Combined with subsetting, you can reach 90%+ reduction.
Should I use font-display: swap for all fonts?
Yes, for most cases. The swap value prevents invisible text (FOIT) by showing fallback fonts immediately, then swapping to your custom font once loaded. This is the best balance for user experience and perceived performance.
What's the break-even point for variable fonts?
Variable fonts typically break even around 3 weights. Below that, individual static font files are smaller. Above 3 weights, the single variable font file becomes more efficient. Most design systems benefit from variable fonts.
Can I subset fonts with user-generated content?
Subsetting isn't recommended for sites with user-generated content where you can't predict what characters users will type. Instead, use unicode-range to let browsers fetch only needed characters from a full font, or accept larger font files.
Does unicode-range automatically subset my font files?
No. Unicode-range controls loading behavior, not file contents. If you set unicode-range but serve a full font file, browsers will still download the entire file — it just won't use it for characters outside the range. You must physically subset the font file and use unicode-range together for optimal performance.