← Back to Course

Module 04

Web Typography

Web fonts, loading strategies, and responsive type scales. Taking typography from design to implementation on the web.

From web-safe fonts to Flash-based sIFR to Cufon to @font-face. The journey to beautiful web typography took decades. Now we have Google Fonts, Adobe Fonts, and variable fonts.

Custom web fonts were revolutionary in 2010. Now they're expected. The trend is toward performance - variable fonts, subsetting, and system font stacks.

Performance matters. Typography must load fast, render well across devices, and remain accessible. These constraints shape every web typography decision.

Part A

Core Concepts

01

Web Font Sources

Where to get web fonts and the trade-offs of each source.

Google Fonts

1,500+ families | Free | CDN-hosted

Google Fonts (Free)

Free, easy to use, huge selection. Downside: Google CDN means tracking concerns and dependency on third-party. Consider self-hosting for privacy.

Adobe Fonts

Premium foundries | Creative Cloud included

Adobe Fonts (Subscription)

High-quality fonts from professional foundries. Included with Creative Cloud. No self-hosting option - requires Adobe's servers.

Self-Hosted Benefits:

  • No third-party requests
  • Better privacy
  • Full caching control
  • Works offline
Self-Hosted Fonts

Download font files and host on your server. Best for performance and privacy. Use tools like google-webfonts-helper to get files.

PREMIUM SOURCES:

  • Type Network
  • Font Bureau
  • Hoefler&Co
  • Grilli Type
  • Commercial Type
Premium Foundries

Professional foundries offer exclusive, high-quality typefaces. Often expensive but unique. Licensing varies - check web license terms carefully.

02

Font Loading

How fonts load and strategies to optimize the experience.

FOIT

Flash of Invisible Text. Browser hides text until font loads. Bad: content invisible.

FOUT

Flash of Unstyled Text. Shows fallback first, swaps when ready. Better UX.

Loading Behaviors

FOIT hides content (bad). FOUT shows fallback fonts first (better). Use font-display: swap to ensure FOUT behavior.

@font-face {
  font-family: 'MyFont';
  src: url('font.woff2');
  font-display: swap;
}
CSS font-display

font-display controls loading behavior. 'swap' shows fallback immediately, swaps when loaded. 'optional' may not swap at all on slow connections.

<link
  rel="preload"
  href="/fonts/inter.woff2"
  as="font"
  type="font/woff2"
  crossorigin
>
Preloading Fonts

Preload tells the browser to fetch fonts early, before CSS is parsed. Reduces load time but use sparingly - preloading too much backfires.

Full font: ~200KB

Subset (Latin): ~20KB

Font Subsetting

Full fonts include all characters (Cyrillic, Greek, etc.). Subsetting removes unused glyphs. Google Fonts does this automatically via unicode-range.

03

Responsive Typography

Making type work across all screen sizes.

h1 { font-size: 2rem; }

@media (min-width: 768px) {
  h1 { font-size: 2.5rem; }
}

@media (min-width: 1024px) {
  h1 { font-size: 3rem; }
}
Type at Breakpoints

Traditional approach: different sizes at different breakpoints. Works but creates jumps. Each breakpoint needs manual tuning.

h1 {
  font-size: calc(1.5rem + 2vw);
}

Type scales smoothly with viewport width

Viewport Units

Viewport units (vw, vh) scale with screen size. Smooth scaling, no jumps. Problem: can get too small or too large at extremes.

h1 {
  /* min, preferred, max */
  font-size: clamp(1.5rem, 4vw, 3rem);
}

Never smaller than 1.5rem, never larger than 3rem

CSS clamp() Function

clamp(min, preferred, max) is the best of both worlds. Fluid scaling with enforced limits. The modern solution for responsive typography.

:root {
  --step--1: clamp(0.83rem, 0.8rem + 0.15vw, 0.94rem);
  --step-0: clamp(1rem, 0.95rem + 0.24vw, 1.19rem);
  --step-1: clamp(1.2rem, 1.12rem + 0.38vw, 1.5rem);
  --step-2: clamp(1.44rem, 1.32rem + 0.58vw, 1.88rem);
  --step-3: clamp(1.73rem, 1.55rem + 0.87vw, 2.34rem);
}
Type Scale Systems

Use tools like utopia.fyi to generate complete fluid type scales. Each step scales proportionally across all viewport sizes.

04

System Font Stacks

Using native operating system fonts for maximum performance.

body {
  font-family:
    system-ui,
    -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    sans-serif;
}
The system-ui Stack

system-ui uses the OS native font. San Francisco on macOS/iOS, Segoe UI on Windows, Roboto on Android. Zero load time, native feel.

Good for:

  • Admin dashboards
  • Documentation sites
  • Performance-critical apps
  • Native-feeling PWAs
  • MVP and prototypes
System Fonts Use Cases

System fonts work great when brand identity isn't primary. GitHub, Bootstrap docs, and many admin tools use system fonts.

PROS

  • Zero load time
  • Native look and feel
  • Excellent rendering
  • No licensing issues

CONS

  • Less brand control
  • Varies by OS
  • Can't guarantee appearance
  • No unique identity
Pros and Cons

System fonts trade brand uniqueness for performance. Perfect for applications, potentially limiting for marketing sites.

code {
  font-family:
    ui-monospace,
    SFMono-Regular,
    Menlo,
    Monaco,
    Consolas,
    monospace;
}
System Monospace

ui-monospace targets system monospace fonts. Great for code blocks without loading a custom coding font.

05

Performance Optimization

Making web fonts as fast as possible.

1Use WOFF2 format (smallest)
2Subset to needed characters
3Self-host when possible
4Preload critical fonts
5Use font-display: swap
6Limit to 2-3 weights
Performance Checklist

Each optimization compounds. A font that was 200KB becomes 20KB subsettd, loads in parallel with HTML, and shows fallback text immediately.

One file

All weights

100-900 and everything between

Variable Fonts

Variable fonts contain all weights in one file. Instead of 4 files (regular, medium, semibold, bold), one variable font file covers everything.

LCP

Largest Contentful Paint - when main content visible

CLS

Cumulative Layout Shift - text reflow when fonts swap

FCP

First Contentful Paint - when any content appears

TTI

Time to Interactive - when page is usable

What to Measure

Font loading affects Core Web Vitals. Slow fonts hurt LCP. Font swaps cause CLS. Optimize fonts to improve these metrics.

@font-face {
  font-family: 'Inter';
  src: url('inter.woff2');
  /* Adjust fallback to match */
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
  size-adjust: 107%;
}
Reducing Layout Shift

When fallback font swaps to web font, size differences cause layout shift. CSS overrides can make fallback metrics match the web font.

Part G

CSS Implementation

14

CSS Implementation

Production-ready web typography code.

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2');
  font-weight: 100 900;  /* Variable font range */
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153;
}
Complete @font-face via CSS
  • font-weight: 100 900 - Variable font weight range
  • font-display: swap - Show fallback while loading
  • unicode-range - Only load for these characters
:root {
  --font-sm: clamp(0.875rem, 0.8rem + 0.25vw, 1rem);
  --font-base: clamp(1rem, 0.9rem + 0.4vw, 1.25rem);
  --font-lg: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
  --font-xl: clamp(1.5rem, 1.2rem + 1vw, 2rem);
  --font-2xl: clamp(2rem, 1.5rem + 1.5vw, 3rem);
}

h1 { font-size: var(--font-2xl); }
p { font-size: var(--font-base); }
Fluid Type Scale via CSS
  • clamp(min, pref, max) - Fluid with constraints
  • CSS variables - Reusable scale values
  • vw in preferred - Scales with viewport




Preload Critical Font via CSS
  • rel="preload" - High priority fetch
  • as="font" - Tells browser the resource type
  • crossorigin - Required for fonts, even same-origin
:root {
  --font-sans: system-ui, -apple-system, BlinkMacSystemFont,
    'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo,
    Monaco, Consolas, 'Courier New', monospace;
}

body { font-family: var(--font-sans); }
code { font-family: var(--font-mono); }
System Font Stack via CSS
  • system-ui - OS default UI font
  • ui-monospace - OS default monospace
  • Fallback chain - Works on all platforms

Part H

Self-Assessment

15

Self-Assessment

Test your web typography knowledge.

Q1

What does font-display: swap do?

Click to reveal
Q2

Why should you self-host fonts instead of using Google Fonts CDN?

Click to reveal
Q3

What is font subsetting?

Click to reveal
Q4

How does clamp() improve responsive typography?

Click to reveal
Q5

When should you use system fonts instead of web fonts?

Click to reveal

Key Takeaways

font-display: swap always

font-display: swap

Content should never be invisible while waiting for fonts. font-display: swap ensures fallback text is visible immediately.

Own your fonts

Self-hosted fonts = better performance + privacy

Self-hosting eliminates third-party dependencies, improves caching, protects privacy, and often loads faster than CDNs.

clamp() for fluid type
font-size: clamp(1rem, 2vw, 2rem)

clamp() creates smooth scaling with min/max constraints. No breakpoint jumps, no extreme sizes. The modern responsive typography solution.

WOFF2 + subset + limit weights

Target: <100KB total fonts

WOFF2 format, character subsetting, and limiting to 2-3 weights keeps font payload small. Each KB matters for performance.