How to Reduce Font File Size: Complete Optimization Guide
Comprehensive guide to reducing font file sizes through compression, subsetting, and format optimization. Improve page load times and performance without sacrificing quality.
In Simple Terms
Three main techniques: Convert to WOFF2 (60-70% smaller), subset to Latin characters (50-80% smaller), and limit font weights (2-3 instead of 6+).Target: Under 100KB total for all fonts. A typical optimized setup is 14-28KB per weight in WOFF2 format with Latin subset.Tools: Glyphhanger (auto-scans your site), pyftsubset (CLI), or Font Squirrel (web GUI). Always keep original fonts as backup.
In this article
Large font files significantly impact website performance, slowing down page loads and consuming bandwidth. A typical web font family with multiple weights and styles can easily exceed 500KB-1MB, creating a noticeable delay in text rendering and overall user experience. For users on slower connections or mobile devices, this delay becomes even more pronounced, potentially leading to higher bounce rates and reduced engagement.
Font optimization is one of the most effective performance improvements you can make. By reducing font file sizes through compression, subsetting, and format optimization, you can achieve 70-95% size reductions while maintaining full visual quality for your specific use case. A well-optimized font implementation typically uses 20-50KB per weight instead of 200-500KB, dramatically improving load times without any visible degradation.
This guide covers everything from analyzing your current font files to implementing aggressive optimization strategies. You'll learn practical techniques for font subsetting (removing unused characters), format conversion to modern compressed formats, advanced compression methods, and how to measure the impact of your optimizations. Whether you're dealing with Google Fonts, custom typefaces, or icon fonts, these techniques will help you achieve optimal performance.
Understanding Font File Size
What Makes Font Files Large?
1. Character Coverage
- • Full Unicode fonts: 50,000+ characters (Chinese, Japanese, Korean)
- • Latin Extended: 1,000-2,000 characters (accents, special symbols)
- • Basic Latin only: 100-200 characters (A-Z, a-z, 0-9, punctuation)
- • Each character adds data: glyph outline, metrics, kerning pairs
- • Most websites use only 200-400 unique characters
2. Font Features and Hinting
- • OpenType features: Ligatures, alternates, stylistic sets
- • TrueType hinting: Instructions for pixel-perfect rendering at small sizes
- • Kerning tables: Spacing adjustments between character pairs
- • Metadata: Font names, licensing, versioning information
- Feature-rich fonts can be 2-3× larger than minimal versions
3. File Format Efficiency
- • TTF/OTF: Uncompressed, largest file sizes (100-500KB per weight)
- • WOFF: ZIP compression applied to TTF/OTF (40-60% smaller)
- • WOFF2: Brotli compression + optimized tables (50-70% smaller than WOFF)
- • EOT: Legacy IE format, usually larger than WOFF
- Modern WOFF2 is typically 20-30KB for basic Latin subset
4. Multiple Weights and Styles
- • Each weight (Light, Regular, Medium, Bold, Black) is a separate file
- • Each style (Normal, Italic) doubles the number of files
- • Complete family: 8-16 files totaling 1-4MB unoptimized
- • Variable fonts can replace multiple weights in single file
Typical Font File Sizes
Why Font Size Matters
Performance Impact
Page Load Time: 500KB of fonts adds 1-3 seconds on 3G connections
Render Blocking: Fonts block text rendering until loaded (FOIT)
Bandwidth Cost: Large fonts consume mobile data allowances
Cache Size: Bloated cache reduces effectiveness of browser caching
Core Web Vitals: Large fonts negatively impact LCP and CLS metrics
User Experience Impact
Perceived Performance: Users notice delays over 100ms
Mobile Users: 60% of traffic on mobile sees amplified font loading delays
Bounce Rate: 53% of users abandon sites that take 3+ seconds to load
Accessibility: Slow loads particularly impact users with disabilities
Business Impact
SEO Rankings: Page speed is a Google ranking factor
Conversion Rates: 1 second delay = 7% reduction in conversions
CDN Costs: Bandwidth charges multiply with large font files
Mobile Performance: Better scores in mobile-first indexing
Analyzing Font Files
Step 1: Check Current Font Sizes
Browser DevTools Network Tab:
- Open DevTools (F12)
- Go to Network tab
- Filter by "Font"
- Refresh page (Ctrl+R)
- Note file names and sizes
- Check "Size" vs "Transferred" columns
Step 2: Analyze Character Usage
Command Line Analysis (fonttools):
# Install fonttools pip install fonttools brotli # Get glyph count ttx -l font.ttf | grep "glyf" -A 1 # List all characters ttx -t cmap font.ttf # Get detailed font info ttx -o font.ttx font.ttf
Online Tools:
- • FontDrop! (fontdrop.info) - Drag & drop font analysis
- • Wakamaifondue (wakamaifondue.com) - Detailed font feature inspection
- • FontSquirrel Webfont Generator - Shows glyph count and size estimates
Step 3: Identify Actual Character Usage
Analyze your website content to determine which characters you actually use:
// JavaScript to extract unique characters
const uniqueChars = new Set(
document.body.innerText.split('')
);
console.log('Unique characters:', uniqueChars.size);
console.log('Characters:', Array.from(uniqueChars).sort().join(''));
// Copy to clipboard
navigator.clipboard.writeText(
Array.from(uniqueChars).sort().join('')
);Run this in browser console to see exactly which characters your site uses
Compression Methods
Method 1: Convert to WOFF2 (Highest Priority)
Impact: 50-70% size reduction vs TTF/OTF, 30-40% vs WOFF
Using fonttools (Recommended):
# Install fonttools with WOFF2 support
pip install fonttools brotli
# Convert single file
ttx -f -o output.woff2 input.ttf
# OR use woff2_compress directly
woff2_compress input.ttf
# Batch convert all TTF files
for file in *.ttf; do
ttx -f -o "${file%.ttf}.woff2" "$file"
doneUsing Online Tools:
- • CloudConvert: Batch conversion, preserves metadata
- • font-converter.net: Simple drag-and-drop interface
- • Online Font Converter: Multiple format output
Method 2: Strip Unnecessary Data
Impact: 5-15% additional size reduction
# Remove hinting (if not needed) pyftsubset font.ttf \ --drop-tables+=DSIG,GDEF,GPOS,GSUB,hdmx,kern,LTSH,prep,VDMX \ --output-file=font-no-hinting.ttf # Remove OpenType features pyftsubset font.ttf \ --layout-features- \ --output-file=font-no-features.ttf # Remove name table bloat pyftsubset font.ttf \ --name-IDs='*' \ --name-legacy \ --name-languages='*' \ --output-file=font-minimal.ttf
Method 3: Use Variable Fonts
Impact: One variable font file replaces 4-8 static weight files
Before: Regular (100KB) + Medium (105KB) + Bold (110KB) + Black (115KB) = 430KB
After: Variable font with weight axis (100-900) = 120KB
/* CSS usage */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-variable.woff2') format('woff2-variations');
font-weight: 100 900; /* Full range */
}
/* Use any weight value */
h1 { font-weight: 350; }
h2 { font-weight: 650; }Font Subsetting Techniques
Technique 1: Basic Latin Subsetting
Impact: 70-90% size reduction for English-only sites
# Basic Latin (A-Z, a-z, 0-9, punctuation) pyftsubset font.ttf \ --output-file=font-basic-latin.woff2 \ --flavor=woff2 \ --unicodes="U+0020-007F" # Result: 200KB → 20KB (90% reduction)
Technique 2: Latin Extended Subsetting
Impact: 60-80% size reduction, supports European languages
# Latin Extended (includes accents: é, ñ, ü, etc.) pyftsubset font.ttf \ --output-file=font-latin-ext.woff2 \ --flavor=woff2 \ --unicodes="U+0020-007F,U+00A0-00FF,U+0100-017F" # Result: 200KB → 40KB (80% reduction)
Technique 3: Custom Character Set
Impact: Maximum optimization for specific content
Create text file with your characters:
# Save your actual content to chars.txt echo "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,!?" > chars.txt # Subset using text file pyftsubset font.ttf \ --output-file=font-custom.woff2 \ --flavor=woff2 \ --text-file=chars.txt
Advanced: Multiple Subsets with unicode-range:
/* Create multiple subsets for progressive loading */
/* Latin subset */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-latin.woff2') format('woff2');
unicode-range: U+0020-007F;
}
/* Latin Extended subset */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-latin-ext.woff2') format('woff2');
unicode-range: U+0100-017F;
}
/* Only loads when characters in range are used */Technique 4: Automated Subsetting with Google Fonts
Impact: Google automatically subsets and serves optimal files
<!-- Only loads Latin subset automatically --> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet"> <!-- Specify subset explicitly --> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&subset=latin&display=swap" rel="stylesheet"> <!-- Multiple subsets --> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&subset=latin,latin-ext&display=swap" rel="stylesheet">
Format Optimization
| Format | Compression | Browser Support | Recommended Use |
|---|---|---|---|
| WOFF2 | Best (Brotli) 50-70% smaller than TTF | 97% of browsers All modern browsers | ✓ Primary format ✓ Use for all modern sites |
| WOFF | Good (ZIP) 40-60% smaller than TTF | 99% of browsers IE9+, all modern browsers | ✓ Fallback for IE11 ✓ Legacy browser support |
| TTF/OTF | None Baseline size | Universal All browsers, desktop apps | ✗ Avoid for web ✓ Source files only |
| EOT | Poor Similar to TTF | IE6-8 only Legacy format | ✗ Obsolete Only if supporting IE8 |
Optimal Format Strategy
/* Modern approach (WOFF2 only) */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2');
font-display: swap;
}
/* With IE11 fallback */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2'),
url('/fonts/myfont.woff') format('woff');
font-display: swap;
}Best practice: WOFF2 primary, WOFF fallback only if supporting IE11
Advanced Optimization Techniques
Technique 1: Font Loading Strategies
Preload Critical Fonts:
<!-- Preload main font for instant rendering -->
<link rel="preload"
href="/fonts/main-font.woff2"
as="font"
type="font/woff2"
crossorigin>
<!-- Load other weights later -->
<link rel="preload"
href="/fonts/bold-font.woff2"
as="font"
type="font/woff2"
crossorigin
media="(max-width: 768px)">Use font-display Effectively:
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2');
/* Options:
swap - Show fallback immediately, swap when loaded
optional - Only use if loads fast (<100ms)
fallback - Brief invisible period, then swap
block - Wait for font (default, slow) */
font-display: swap; /* Recommended for most cases */
}Technique 2: Dynamic Subsetting
Load only the characters you need based on page content
/* Split font into multiple unicode-range subsets */
/* Numbers only (small) */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-numbers.woff2') format('woff2');
unicode-range: U+0030-0039;
}
/* Common letters (medium) */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-common.woff2') format('woff2');
unicode-range: U+0041-005A, U+0061-007A;
}
/* Special characters (loads only if needed) */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-special.woff2') format('woff2');
unicode-range: U+00A0-00FF;
}
/* Browser automatically loads only required subsets */Technique 3: Self-Host Google Fonts
Download and optimize Google Fonts for better control and performance
Using google-webfonts-helper:
- Visit google-webfonts-helper.herokuapp.com
- Search for your font (e.g., "Roboto")
- Select charsets (Latin, Latin Extended)
- Select styles (Regular 400, Bold 700)
- Download optimized WOFF2 files
- Copy generated CSS
Benefits: No external requests, better compression, full control over subset
Technique 4: Icon Font Optimization
Reduce icon font sizes by removing unused icons
# Subset FontAwesome to only used icons pyftsubset fontawesome.ttf \ --output-file=fontawesome-minimal.woff2 \ --flavor=woff2 \ --unicodes="U+f015,U+f007,U+f0e0,U+f002" # home, user, envelope, search # Result: 150KB → 8KB (95% reduction) # Alternative: Use IcoMoon or Fontello to build custom icon fonts # with only the icons you need
Implementation Strategy
Step-by-Step Implementation
- Audit Current Fonts
- Measure total font file sizes
- Identify all weights and styles in use
- Check actual character usage on site
- Note current page load times
- Prioritize Optimizations
- Convert to WOFF2 (quick win, 50% reduction)
- Subset to Latin Extended (another 60-80%)
- Remove unused weights
- Consider variable fonts for multiple weights
- Implement Changes
- Create optimized font files
- Update @font-face declarations
- Add font-display: swap
- Implement preload for critical fonts
- Test Thoroughly
- Check all characters render correctly
- Verify fonts load in all target browsers
- Test on slow connections (throttle network)
- Validate no missing glyphs
- Measure Impact
- Compare before/after file sizes
- Measure page load improvement
- Check Core Web Vitals (LCP, CLS)
- Monitor real user metrics
Complete Example: Before & After
❌ Before Optimization (1.2MB total):
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-light.ttf');
font-weight: 300;
}
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-regular.ttf'); /* 250KB */
font-weight: 400;
}
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-medium.ttf'); /* 260KB */
font-weight: 500;
}
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-bold.ttf'); /* 270KB */
font-weight: 700;
}
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-black.ttf');
font-weight: 900;
}
/* 5 files × ~250KB = 1.2MB */✓ After Optimization (85KB total, 93% reduction):
<!-- Preload critical font -->
<link rel="preload"
href="/fonts/myfont-regular-latin.woff2"
as="font"
type="font/woff2"
crossorigin>
/* Regular weight, Latin subset only */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-regular-latin.woff2') format('woff2');
font-weight: 400;
font-display: swap;
unicode-range: U+0020-007F, U+00A0-00FF;
}
/* Bold weight, Latin subset only */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-bold-latin.woff2') format('woff2');
font-weight: 700;
font-display: swap;
unicode-range: U+0020-007F, U+00A0-00FF;
}
/* Removed unused weights: Light (300), Medium (500), Black (900) */
/* 2 files × ~40KB = 85KB (93% reduction!) */Performance Impact
Summary: Effective Font Size Reduction
Reducing font file sizes is one of the highest-impact performance optimizations you can make. By converting to WOFF2, subsetting to only required characters, removing unused weights, and implementing smart loading strategies, you can achieve 70-95% size reductions with zero visual quality loss.
Start with quick wins (WOFF2 conversion), then move to character subsetting, and finally implement advanced techniques like unicode-range splitting and variable fonts. Test thoroughly, measure impact, and prioritize fonts that load early in the page rendering process. Your users will experience faster load times, and you'll save significant bandwidth costs.

Written by
Sarah Mitchell
Product Designer, Font Specialist

Verified by
Marcus Rodriguez
Lead Developer
