PerformanceFont LoadingWeb VitalsCSS

Performance: Font Loading Strategies for Web Apps

Optimize web font loading with font-display, preload, subsetting, and fallback strategies to eliminate FOIT and improve Core Web Vitals for your SaaS.

Taylor Brooks
Taylor Brooks
June 13, 202612 min read

TL;DR: Web fonts block rendering by default, causing Flash of Invisible Text (FOIT). This guide covers font-display, font subsetting, preload hints, and self-hosting to eliminate layout shifts and achieve fast first paint. Learn production patterns at tanstackship.com.

Introduction

Web fonts impact both visual design and performance. A slow font load can delay first contentful paint by several seconds. In 2026, with variable fonts and extensive typography options, font loading optimization is essential for Core Web Vitals scores.

Font Loading Strategy Comparison

StrategyFOIT DurationFOUT RiskComplexityBest For
font-display: swap0msHighLowBody text
font-display: optional100msMediumLowUI icons
font-display: block3sNoneLowBrand headings
Preload + swap0msMediumMediumHero text fonts
Critical font inlining0msLowHighAbove-fold text
Self-hosting (WOFF2)VariesLowMediumAll production use

Implementing font-display

css
/* Optimal font-display for body text */
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2');
  font-display: swap;
  font-weight: 100 900;
  unicode-range: U+0000-00FF;
}

The swap value gives the font a 100ms block period, then swaps to a fallback if the font hasn't loaded. This eliminates invisible text while avoiding layout shifts.

Preloading Critical Fonts

html
<!-- Preload your primary font -->
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin>

<!-- Preload only the weight you need for above-fold content -->
<link rel="preload" href="/fonts/inter-semibold.woff2" as="font" type="font/woff2" crossorigin>

Preloading moves font discovery to the initial HTML parsing phase, before the browser encounters the CSS @font-face declaration.

Font Subsetting for Size Reduction

TechniqueSize ReductionImplementation
Basic Latin subset60-70%pyftsubset or glyphhanger
Variable font subset50-60%Combined axis + character subset
Unicode-range splitting40-50%CSS unicode-range per @font-face
WOFF2 compression30-50%Automatic with modern tools
bash
# Subset a font to basic Latin with glyphhanger
npx glyphhanger https://your-site.com --subset=*.ttf --formats=woff2

# Result: Font file reduced from 150KB to 45KB

Self-Hosting vs Google Fonts

ts
// Self-hosted font loading in TanStack Start
import { defineFont } from '~/lib/fonts'

export const primaryFont = defineFont({
  src: '/fonts/inter-var.woff2',
  display: 'swap',
  preload: true,
  fallback: {
    fontFamily: 'system-ui',
    sizeAdjust: '105%'  // Match metrics to reduce layout shift
  }
})

Self-hosting eliminates the DNS lookup, TCP connection, and TLS negotiation to Google's servers, saving 200-400ms on first load.

Conclusion

Font loading optimization directly impacts Largest Contentful Paint and Cumulative Layout Shift. Prioritize self-hosting WOFF2 fonts, use font-display: swap for body text, preload critical fonts, and subset aggressively. These techniques ensure your typography enhances rather than hinders user experience.

For the full picture, see our Preload, Prefetch, and Preconnect Guide for resource hint best practices, and Critical CSS and Inlining Strategies for CSS delivery optimization. Combine with the Core Web Vitals Optimization Guide and CDN Selection and Configuration Guide for a complete performance strategy.