Typography & Design Systems5 min read

Web Font Performance: Preloading, Subsetting, and Reducing CLS

How loading full web font families destroys Core Web Vitals, and how font subsetting, WOFF2 compression, and font-display: swap eliminate Cumulative Layout Shift.

AS
Written by Anuj Shrivastava
Engineering & UI Architecture
🚀

Live Interactive Demonstration

Try the principles discussed in this article directly on our live tool.

Inspect Dynamic Font Loading in Type Lab →

A single web font family with 4 weights (Regular, Medium, SemiBold, Bold) can easily weigh over 400KB if not optimized.

When a visitor lands on your website over mobile 4G, their browser encounters the dreaded FOIT (Flash of Invisible Text) or FOUT (Flash of Unstyled Text). When the custom font finally pops in, lines reflow, paragraphs jump, and your Google Cumulative Layout Shift (CLS) score plummets into the red.

Here is the engineering playbook to make custom web fonts load with zero layout shift.


1. Eliminate Layout Shift with size-adjust and Fallback Overrides

When custom web fonts load, their x-height and letter dimensions rarely match the fallback font (Arial or Times New Roman). When the custom font replaces the system fallback, content shifts vertically.

Modern CSS allows you to match fallback metrics to your custom font:

/* Define an adjusted fallback that matches Inter's physical footprint */
@font-face {
  font-family: 'Inter-Fallback';
  src: local('Arial');
  ascent-override: 90%;
  descent-override: 22.5%;
  line-gap-override: 0%;
  size-adjust: 107.5%;
}

body {
  font-family: 'Inter', 'Inter-Fallback', sans-serif;
}

2. Font Subsetting: Why You Don’t Need 2,000 Unused Glyphs

A standard full Unicode font file contains glyphs for Cyrillic, Greek, mathematical symbols, arrows, and currency signs. If your application only serves English, Spanish, and French users, 80% of the font file is wasted bandwidth.

  • Full Font File: ~120KB per weight
  • Latin-Subsetted WOFF2: ~14KB per weight (an 88% reduction!)
<!-- Load only the Latin glyph subset from Google Fonts -->
<link 
  rel="stylesheet" 
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&subset=latin&display=swap" 
/>

3. The Modern Font Loading Triad

<!-- 1. Preconnect to font CDN domains -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />

<!-- 2. Preload the primary body Regular font weight -->
<link 
  rel="preload" 
  href="/fonts/inter-latin-400.woff2" 
  as="font" 
  type="font/woff2" 
  crossorigin 
/>

<!-- 3. Always use font-display: swap in CSS -->
<style>
  @font-face {
    font-family: 'CustomFont';
    src: url('/fonts/custom.woff2') format('woff2');
    font-display: swap; /* Immediately renders fallback, swaps smoothly */
  }
</style>

Summary Checklist for 100/100 Core Web Vitals:

  1. Use WOFF2 exclusively (ignore legacy TTF/EOT).
  2. Subset your glyphs to the target audience languages.
  3. Preload only the single most critical font weight (e.g., Body Regular).
  4. Use font-display: swap to prevent Flash of Invisible Text.

Explore Popular High-Performance Web Fonts in Type Lab →

More from the IpsumForge Engineering Blog