Font Compression: WOFF vs WOFF2
Compare WOFF (zlib) and WOFF2 (Brotli) compression algorithms. Understand why WOFF2 achieves 30% better compression and when to use each format.
Key Takeaways
- • WOFF uses zlib (DEFLATE); WOFF2 uses Brotli + preprocessing
- • WOFF2 is typically 20-30% smaller than WOFF
- • Both have 97%+ browser support; use WOFF2 primarily
- • Subsetting provides greater savings than compression alone
In this article
Web font formats use compression to reduce file sizes for faster delivery. WOFF (Web Open Font Format) was the first web-specific font format, using zlib compression. WOFF2 replaced it with Brotli compression plus font-specific preprocessing, achieving significantly better results.
Font data has distinctive compression characteristics compared to text or binary executables. A typical OpenType font contains several data types with different entropy profiles: the glyph outline data in the glyf or CFF table consists of coordinate sequences with small delta values between consecutive points; the horizontal metrics table (hmtx) stores advance widths that cluster around the font's predominant character width; and layout tables (GSUB, GPOS) contain highly regular structural patterns from their record formats. General-purpose compressors like zlib can exploit this repetition, but font-specific preprocessing reorganizes the data into streams with even higher regularity before compression, which is why WOFF2 outperforms WOFF by more than Brotli alone would account for.
The practical impact of compression on page load time depends on the network context. On modern broadband connections, the difference between a 150KB WOFF and a 115KB WOFF2 may be imperceptible in isolation. However, fonts are typically render-blocking resources—the browser must download and parse a font before it can display text using that font. A 25% smaller file directly reduces the time before text appears, which affects Core Web Vitals metrics like Largest Contentful Paint and Time to First Contentful Paint. For applications serving global audiences across varied network conditions, WOFF2's compression advantage compounds with geographic CDN distribution to produce meaningful user experience improvements.
Format Comparison
| Aspect | WOFF | WOFF2 |
|---|---|---|
| Algorithm | zlib (DEFLATE) | Brotli + preprocessing |
| Compression vs TTF | 40-50% smaller | 55-65% smaller |
| WOFF2 vs WOFF | — | 20-30% smaller |
| Browser Support | 99%+ (IE9+) | 97%+ (2015+) |
| Decompression Speed | Fast | Slightly slower* |
| Specification | W3C 2012 | W3C 2018 |
*Brotli decompression is marginally slower than zlib, but the difference is negligible for typical font file sizes. The smaller download time more than compensates.
Real-World Size Benchmarks
Actual compression ratios vary by font complexity. Latin-only text fonts compress more efficiently than CJK fonts with thousands of glyphs. These measurements are from common production fonts:
| Font | TTF Size | WOFF | WOFF2 | WOFF2 vs WOFF |
|---|---|---|---|---|
| Inter Regular (Latin) | 308 KB | 181 KB | 142 KB | −22% |
| Noto Sans (Latin+Greek+Cyrillic) | 556 KB | 298 KB | 228 KB | −23% |
| Source Serif 4 Variable | 890 KB | 541 KB | 391 KB | −28% |
| Subset Latin (pyftsubset) | 40 KB | 24 KB | 18 KB | −25% |
Values approximate. Actual sizes depend on font content, hinting data, and OpenType table count. Variable fonts compress especially well in WOFF2 due to delta encoding in gvar table preprocessing.
WOFF 1.0: zlib Compression
WOFF wraps font data with a new header and compresses each table independently using zlib (the same algorithm used by gzip). It's straightforward but not optimized for font data.
WOFF 1.0 File Structure
├── WOFF Header (44 bytes)
│ ├── signature: "wOFF"
│ ├── flavor: font type (TrueType/CFF)
│ ├── length: total file size
│ └── numTables, totalSfntSize, etc.
│
├── Table Directory
│ └── [tag, offset, compLength, origLength, origChecksum]
│
└── Compressed Table Data
├── Each table compressed separately with zlib
└── Tables < compLength uncompressedWOFF's zlib (DEFLATE) compression is the same algorithm used in gzip and ZIP files. It operates as a general-purpose compressor with no font-specific optimizations. Each table is compressed independently, which means patterns that span table boundaries cannot be exploited. The compression level (1–9) can be tuned during WOFF generation, with level 6 being the common default that balances speed and compression ratio.
When WOFF Is Still Appropriate
Supporting IE11: While IE11 support has declined dramatically, sites with legacy traffic can use WOFF as the exclusive fallback since IE11 does not support WOFF2.
Corporate intranets: Environments with locked-down browsers on older OS versions may lack WOFF2 support. A WOFF fallback ensures universal rendering.
Rapid prototyping: WOFF is faster to generate than WOFF2 (no Brotli encoding step), making it useful for development environments where iteration speed matters more than file size.
WOFF's zlib (DEFLATE) compression operates as a two-stage algorithm: LZ77 for finding repeated byte sequences within a 32KB sliding window, followed by Huffman coding to encode those matches and literal bytes with variable-length bit codes proportional to their frequency. The 32KB window limit is a meaningful constraint for font data: the glyf table in a large Latin font might span 200KB, so patterns in glyphs near the beginning of the table fall outside the window when processing glyphs near the end. Higher zlib compression levels (1–9) extend the pattern search and produce smaller output at the cost of longer compression time; decompression speed is largely constant regardless of compression level. Level 6 is the common default, balancing compression ratio against generation time.
WOFF2: Brotli + Preprocessing
WOFF2 doesn't just use a better compression algorithm—it first transforms font data into a more compressible format, then applies Brotli compression.
WOFF2 Preprocessing Steps
Glyph Data Transform
Converts TrueType glyf table to more compressible format
loca Table Reconstruction
loca table is omitted (reconstructed from glyf)
hmtx Optimization
Delta-encodes horizontal metrics for better compression
Brotli Compression
All transformed data compressed with Brotli
Why Preprocessing Matters
Brotli alone would give ~10% improvement over zlib. The font-specific preprocessing contributes the other ~20%. This preprocessing recognizes patterns specific to font data that generic compression misses.
How Brotli Achieves Superior Compression
Brotli (developed by Google in 2013) uses three key techniques that outperform DEFLATE for font data: a larger sliding window for back-references (up to 16MB vs zlib's 32KB), a static dictionary of common byte sequences pre-loaded into the compressor, and second-order context modeling that predicts byte values based on the previous two bytes rather than just one.
For WOFF2 specifically, the glyph data transform is what makes the biggest difference. Before Brotli compression, the glyf table is restructured: coordinate data is separated from flags, x-coordinates and y-coordinates are stored in separate streams, and delta encoding converts absolute coordinates to smaller delta values. This preprocessing converts a table full of large mixed values into streams of small, highly regular numbers—exactly what Brotli's context modeling excels at compressing.
# Converting TTF to WOFF2 with Python fonttools from fontTools.ttLib import TTFont from fontTools import ttLib import brotli # pip install brotli # Using woff2 command-line tool (recommended) # pip install brotli fonttools[woff] python -m fonttools ttLib.woff2 compress myfont.ttf # Output: myfont.woff2 # Size comparison # myfont.ttf = 245,890 bytes # myfont.woff = 148,230 bytes (−40%) # myfont.woff2 = 113,450 bytes (−54% from TTF, −23% from WOFF)
Practical Recommendations
/* Optimal @font-face declaration */
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2'),
url('myfont.woff') format('woff');
font-display: swap;
}
/* Order matters: browsers use first supported format */
/* WOFF2 first → most browsers use it */
/* WOFF fallback → IE11 and very old browsers */
/* No need for TTF/OTF in @font-face anymore */
/* 97%+ support for WOFF2, 99%+ for WOFF */Always Use WOFF2 Primary
97%+ browser support, best compression. Include WOFF as fallback for the remaining 2%.
Subset Before Compressing
Subsetting provides 70-90% reduction vs 30% from compression. Do both for optimal size.
Compression vs Subsetting: Prioritize Correctly
Developers often focus on compression format (WOFF vs WOFF2) when subsetting provides far larger gains. Consider a typical font serving only English content:
Subsetting to Basic Latin characters (U+0020–U+007E) plus common punctuation reduces font size by 85–93% compared to the full font. Compression then provides an additional 20–25% on top of that. Always subset first, then compress.
Convert to Optimal Web Formats
Our converter produces optimally compressed WOFF and WOFF2 files.
Try Font ConverterWritten by
Sarah Mitchell
Product Designer, Font Specialist
Verified by
Marcus Rodriguez
Lead Developer
Compression FAQs
Common questions about WOFF and WOFF2 compression
