In one sentence
Font subsetting and conversion is like packing for a weekend getaway: instead of lugging around a 6,000-character suitcase filled with Cyrillic scripts and dingbats you'll never use, you pack only the exact letters you need into a highly compressed, web-ready backpack.
The problem it solves
If you were building websites in 2005, your typographic palette was basically a hostage situation. You had Arial, Times New Roman, Georgia, Verdana, and maybe Comic Sans if you wanted to watch the world burn. These were "web-safe" fonts—meaning we crossed our fingers and hoped they were already installed on the user’s operating system.
Then came the @font-face revolution. Suddenly, designers could embed any custom typeface they wanted. The web became beautiful, but it also became incredibly slow.
Standard desktop fonts (TrueType or OpenType) are designed for print and universal language support. A single .ttf file might contain thousands of glyphs, supporting English, Greek, Vietnamese, specialized math symbols, and twenty variations of the ampersand. This is fantastic for a word processor, but catastrophic for a web browser over a flaky 3G connection. Downloading a 400KB font file blocks rendering, causing the dreaded "Flash of Unstyled Text" (FOUT) or, worse, the "Flash of Invisible Text" (FOIT).
We needed two things to fix this typographic obesity:
- Better compression specifically designed for the web (hence, formats like WOFF and WOFF2).
- Subsetting, the surgical removal of every character and language table that a specific website doesn't actually need.
How it works under the hood
To understand how we shrink fonts, you have to understand what a font file actually is. A modern font (like TTF or OTF) isn't just a folder of vector drawings. It's a complex, binary database based on the SFNT container format.
The Anatomy of a Font
Inside an SFNT container, data is organized into specific tables:
glyforCFF: The actual vector drawings (the curves and lines of the letters).cmap: The character map, which translates a Unicode point (likeU+0041for 'A') to the specific drawing in theglyftable.GSUB/GPOS: Advanced OpenType features like ligatures (connecting 'f' and 'i') and kerning (the spacing between specific letter pairs).name: Metadata like the font name, copyright, and designer info.
The Magic of Subsetting
When you subset a font, a parser cracks open this SFNT container. You give it a list of characters—say, just the basic English alphabet, numbers, and common punctuation.
The parser doesn't just delete the unused vector drawings from the glyf table. It has to meticulously rebuild the entire database. It rewrites the cmap to remove the abandoned Unicode points. It combs through the GSUB and GPOS tables, stripping out kerning pairs for letters that no longer exist, ensuring the file doesn't break. Finally, it recalculates the memory offsets for the file headers.
A standard 300KB font can easily drop to 15KB when subset to just basic Latin characters.
The Format Wars: WOFF and WOFF2
Once the font is subset, it's time to compress it.
| Format | Compression Tech | The Verdict |
|---|---|---|
| TTF / OTF | None (Usually) | Great for desktop design apps. Terrible for web delivery. |
| WOFF | Zlib | The original Web Open Font Format. Good, but outdated. |
| WOFF2 | Brotli | The modern standard. Transforms font tables before compressing them. |
WOFF2 is the undisputed king of web fonts. It doesn't just take a TTF and zip it. WOFF2 physically transforms the SFNT tables—specifically grouping similar data types together—so that the underlying Brotli compression algorithm can find longer repeating patterns. This results in file sizes up to 30% smaller than WOFF1, and potentially 95% smaller than the original TTF when combined with subsetting.
Tying it together with CSS
Once you have your highly compressed, subsetted WOFF2 file, you tell the browser about it using CSS. The unicode-range property is crucial here. It tells the browser, "Only download this file if a character on the page actually matches this range."
@font-face {
font-family: 'MyCustomFont';
/* Load the highly compressed WOFF2 format */
src: url('mycustomfont-subset.woff2') format('woff2');
/* Only trigger the download if the page uses basic Latin characters */
unicode-range: U+0000-00FF, U+0131, U+0152-0153;
font-display: swap;
}
Real-world stories
The "Just an Ampersand" Catastrophe
A boutique design agency was building a landing page for a high-end restaurant. The headline typography looked amazing, primarily because they used a beautiful, ornate cursive font exclusively for the ampersand (&) in the restaurant's name: "Salt & Ash".
However, Lighthouse performance scores were deep in the red. The developers realized they were forcing users to download a 250KB TTF file just to render a single character. By running the font through a subsetter and extracting only the & character (Unicode U+0026), they generated a WOFF2 file that weighed in at a laughable 800 bytes.
The lesson: Never load a full font family for decorative drop-caps, icons, or single characters. Subset aggressively.
The Multi-Lingual Megabyte
A SaaS company localized their marketing site for users in Japan and South Korea. To keep the branding consistent, they embedded a highly respected CJK (Chinese, Japanese, Korean) font. CJK fonts are notoriously massive because they contain tens of thousands of ideograms. The file was 4.5MB.
Suddenly, their users in the US and Europe were waiting seconds for the text to appear, because the browser was downloading 4.5MB of Asian characters they would never see. The engineering team fixed this by subsetting the master font into multiple smaller "chunks" (one WOFF2 for Basic Latin, one for Hiragana/Katakana, etc.) and deploying them with @font-face blocks using strict unicode-range descriptors. Browsers now only downloaded the 15KB Latin chunk for English users.
The lesson: Use subsetting and unicode-range to dynamically serve typographic chunks based on the user's actual language needs.
Common mistakes and traps
- Accidentally deleting the spacebar: When typing out the literal characters you want to subset (e.g.,
abcdefghijklmnopqrstuvwxyz), developers frequently forget to include the space character (U+0020). Without it, your carefully crafted custom font will fall back to Arial every time there's a gap between words, resulting in a horrifying ransom-note aesthetic. - Serving legacy formats unnecessarily: Many developers still generate and serve EOT, TTF, and SVG fonts in their CSS stacks "just to be safe." Don't. WOFF2 is supported by over 97% of browsers globally. Serve WOFF2, maybe provide WOFF as a fallback for ancient browsers, and stop there.
- Stripping essential OpenType features: Aggressive subsetting tools sometimes offer to strip out
GSUBandGPOStables to save a few extra kilobytes. If your font relies on complex ligatures (like turning->into an arrow) or relies heavily on kerning to not look terrible, stripping these tables will ruin the typography. - Forgetting
font-display: swap: Even a tiny 12KB subsetted WOFF2 takes a few milliseconds to download. If you don't includefont-display: swapin your CSS, modern browsers will hide your text completely until the font arrives. Give your users system text to read while the custom font is on its way.
Why it belongs on your radar
Web fonts are historically one of the worst offenders when it comes to ruining Web Vitals. If you care about Largest Contentful Paint (LCP) or Cumulative Layout Shift (CLS), you have to care about font delivery.
You should think about font subsetting and conversion the moment you receive a .ttf or .otf file from a designer or download one from a foundry. Serving raw desktop fonts on the web is the equivalent of serving a raw, uncompressed 10MB bitmap image instead of a WebP.
By converting to WOFF2 and stripping out the thousands of glyphs you aren't using, you reduce bandwidth costs, lower the carbon footprint of your application, and ensure your site is actually readable the millisecond a user clicks your link.
Go deeper
- MDN Web Docs: @font-face - The absolute bible on how to implement custom fonts and use
unicode-rangecorrectly in CSS. - W3C WOFF2 Specification - The official technical spec detailing exactly how WOFF2 transforms and compresses SFNT tables.
- RFC 7932: Brotli Compressed Data Format - The IETF documentation for the compression algorithm that gives WOFF2 its superpowers.
- Web.dev: Optimize WebFonts - Google's authoritative guide on minimizing web font payload and preventing layout shifts.
- Google Fonts Knowledge: What is a font? - A deep dive into the SFNT table structure and how glyphs are stored under the hood.