# Font Subsetting

**SHOULD** · **ID:** `content-font-subsetting` · **Category:** content
**Source:** [Rauno](https://interfaces.rauno.me/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/content-font-subsetting

> SHOULD: Subset webfonts to the alphabets/languages actually used and declare `unicode-range` — full font files ship glyphs you never render.

Subset fonts based on content, alphabet, or relevant languages to reduce file size

Full font files include glyphs for many languages and scripts you may not need. Subsetting to only the character ranges used on your site can reduce font file sizes by 80-90%, improving load times significantly. Subset into the right container while you are at it: serve `.woff2` on the web and never ship a raw `.ttf` or `.otf`, which carry no web compression and land roughly 30-50% heavier for exactly the same glyphs (jakubkrehel's choosing-fonts calls them "Desktop only unless there is no other option"; `.woff` is a fallback for very old browsers, nothing more).

## Rule snippet

```tsx
@font-face { font-family: Inter; src: url(/inter-latin.woff2) format("woff2"); unicode-range: U+0000-00FF; }
```

## Bad — do not do this

`content-font-subsetting-bad`

```tsx
export function FontSubsettingBad() {
  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4 space-y-3">
        <h3 className="text-sm font-medium text-foreground">Font Loading</h3>
        <div className="space-y-2">
          <div className="flex justify-between text-sm">
            <span className="text-muted-foreground">Inter-Regular.woff2</span>
            <span className="text-foreground font-mono">312 KB</span>
          </div>
          <div className="w-full bg-muted rounded-full h-2">
            <div className="bg-destructive h-2 rounded-full" style={{ width: '100%' }} />
          </div>
          <p className="text-xs text-muted-foreground">Full font file with all 2,600+ glyphs including Cyrillic, Greek, Vietnamese…</p>
        </div>
        <div className="text-xs text-muted-foreground">Characters used on page: ~80 (Latin only)</div>
      </div>
      <p className="text-xs text-error">Full font file downloaded — wasted bandwidth on unused glyphs</p>
    </div>
  );
}
```

## Good — do this

`content-font-subsetting-good`

```tsx
export function FontSubsettingGood() {
  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4 space-y-3">
        <h3 className="text-sm font-medium text-foreground">Font Loading</h3>
        <div className="space-y-2">
          <div className="flex justify-between text-sm">
            <span className="text-muted-foreground">Inter-Regular-Latin.woff2</span>
            <span className="text-foreground font-mono">24 KB</span>
          </div>
          <div className="w-full bg-muted rounded-full h-2">
            <div className="bg-primary h-2 rounded-full" style={{ width: '8%' }} />
          </div>
          <p className="text-xs text-muted-foreground">Subset font with only Latin glyphs needed for the page content.</p>
        </div>
        <code className="text-xs bg-muted px-2 py-1 rounded text-foreground block">
          unicode-range: U+0000-00FF, U+0131, U+0152-0153;
        </code>
      </div>
      <p className="text-xs text-success">Font subset — 92% smaller, only needed glyphs</p>
    </div>
  );
}
```

## References

- [interfaces.rauno.me](https://interfaces.rauno.me/)
- [jakubkrehel — choosing-fonts.md (formats)](https://raw.githubusercontent.com/jakubkrehel/skills/main/skills/better-typography/choosing-fonts.md)
- [Google Fonts CSS2 API](https://developers.google.com/fonts/docs/css2)
