Claude Cursor GitHub Copilot Skill

web-typography

Select, pair, and implement typefaces for web projects. Use when the user mentions "font pairing", "which typeface", "line height", "responsive typography", "web font loading", "type hierarchy", "variable fonts", "FOUT/FOIT", "typographic scale", or "the text is hard to read". Al

LLM Mart · 0 points · 4 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download wondelai-skills-plugins_ux-design_skills_web-typography-c172996.zip · 25 KB
Part of wondelai/skills — 183 skills

Install

skills CLI npx skills add https://github.com/wondelai/skills/tree/main/plugins/ux-design/skills/web-typography
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install wondelai-skills@llmmart
Git git clone https://github.com/wondelai/skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole wondelai/skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Web Typography

A practical guide to choosing, pairing, and implementing typefaces for the web. The best typography is invisible — it immerses readers in content rather than calling attention to itself.

Core Principle

Typography is the voice of your content. The typeface you choose sets tone before a single word is read — a legal site shouldn't feel playful; a children's app shouldn't feel corporate. Follow the "clear goblet" principle: typography should be like a crystal-clear wine glass, keeping focus on the wine (content), not the glass (type).

Scoring

Goal: 10/10. Score = number of the 10 Quick Diagnostic rows the implementation satisfies. Bands: 9-10 = body 16px+, measure under 75ch, line-height 1.4+, clear level contrast, font payload under 200KB, fallbacks set, survives 200% zoom; 5-6 = readable but missing measure control, fallbacks, or zoom resilience; <=3 = sub-16px body, no measure cap, FOIT, or unreadable hierarchy. Always state the current score and the specific diagnostic rows failing.

Two Contexts for Type

All typography falls into two categories:

Context Purpose Priorities
Type for a moment Headlines, buttons, navigation, logos Personality, impact, distinctiveness
Type to live with Body text, articles, documentation Readability, comfort, endurance

Workhorse typefaces excel at "type to live with" — versatile across sizes, weights, and contexts without drawing attention. Examples: Georgia, Source Sans, Freight Text, FF Meta.

Typography Framework

1. How We Read

Core concept: Understanding reading mechanics is the foundation for every typography decision. Eyes don't scan smoothly — they jump in bursts.

Why it works: Fighting these mechanics creates friction that drives readers away; aligning with them lets readers absorb content faster with less fatigue.

Key insights:

  • Saccades — eyes jump in 7-9 character bursts; line length and letter spacing directly affect saccade efficiency
  • Fixations — eyes pause briefly to absorb content; dense or poorly spaced text slows reading
  • Word shapes (bouma) — experienced readers recognize word silhouettes, not individual letters
  • Legibility vs. readability — legibility is whether characters can be distinguished (a typeface concern); readability is whether text can be comfortably read for extended periods (a typography concern: size, spacing, line length). A legible typeface can still be set unreadably

Product applications:

Context Application Example
Long-form content Optimize for sustained comfort 16-18px body, 1.5-1.7 line height, 45-75 char lines
Dashboard UI Optimize for rapid scanning Distinct weight hierarchy, whitespace between data groups
Mobile reading Account for distance and lighting Larger body (17-18px), higher contrast

Copy patterns:

.prose {
  font-size: 1.125rem;     /* 18px */
  line-height: 1.6;
  max-width: 65ch;          /* ~45-75 characters */
}

See: references/typeface-anatomy.md when you need to name letterform parts (x-height, counter, aperture) or place a face in a classification system to justify a choice.

2. Evaluating Typefaces

Core concept: A typeface must pass technical, structural, and practical quality checks before it earns a place in a project. Beautiful specimens fail on screen.

Why it works: Screen rendering, variable bandwidth, and diverse devices impose constraints print never faced. Rigorous evaluation prevents costly mid-project typeface swaps.

Key insights:

  • Technical quality — consistent stroke weights, even visual color across text blocks, good kerning pairs (AV, To, Ty), complete character set, multiple weights (minimum: regular, bold, italic)
  • Structural assessment — generous x-height (better screen readability), open counters and apertures (a, e, c), distinct letterforms (Il1, O0, rn vs. m)
  • Practical needs — test at actual use sizes on target screens, check file size, verify the license
  • Real content testing — Lorem ipsum hides problems with character frequency, word length, and paragraph rhythm

Product applications:

Context Application Example
Body text selection Prioritize x-height, open counters, even color Source Serif Pro over Didot for long reads
UI/System text Prioritize small-size legibility and weight range Inter or SF Pro for interface elements
Multilingual product Verify glyph coverage for target languages Noto Sans for broad Unicode support

Copy patterns:

/* Stress-test at every actual use size */
body { font-size: 16px; }
.caption { font-size: 0.75rem; }
h1 { font-size: 3rem; }

Ethical boundary: Always verify the web license before shipping a font — desktop/print licenses rarely cover web embedding, and unlicensed use creates real legal liability.

See: references/evaluating-typefaces.md when vetting a candidate face — full quality checklist, red-flags table, and the structural criteria to inspect.

3. Choosing Typefaces

Core concept: Start with purpose, not aesthetics. The content's tone, reading context, and duration should drive selection — not personal preference or trends.

Why it works: Purpose-driven choices feel inevitable rather than arbitrary, and survive stakeholder review because they can be justified with reasoning rather than taste.

Key insights:

  • Define the job first — body text, headlines, and UI elements may each need different faces
  • Match tone to content — a financial report needs a different voice than a bakery menu
  • Check the family — confirm needed weights, italics, and styles exist before committing
  • Safe starting points — body serif: Georgia, Source Serif Pro, Charter; body sans: system fonts, Source Sans Pro, Inter, IBM Plex Sans

Product applications:

Context Application Example
Content-heavy site Workhorse serif or sans for sustained reading Source Serif Pro or Charter for articles
SaaS dashboard Clean sans with strong tabular figures Inter or IBM Plex Sans for data-rich UIs
Accessibility-focused Faces designed for maximum legibility Atkinson Hyperlegible for vision-impaired users

Copy patterns:

/* Web font with system fallback stack */
body {
  font-family: 'Source Sans Pro', -apple-system,
               BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

See: references/evaluating-typefaces.md when narrowing finalists or weighing free vs. paid faces — the side-by-side comparison method and quality-option shortlists.

4. Pairing Typefaces

Core concept: Successful pairings create clear contrast — faces should be obviously different, not confusingly similar. One to two typefaces maximum.

Why it works: Clear structural contrast (serif + sans, light + bold, humanist + geometric) gives each face a distinct role. Faces that are too similar create tension without purpose — readers sense something is "off" without knowing why.

Key insights:

  • Contrast types — structure (serif + sans), weight (light + regular), era (humanist + geometric), width (condensed + normal)
  • Same designer strategy — faces by one designer often share harmonizing DNA (FF Meta + FF Meta Serif)
  • Superfamilies — families designed to work together eliminate guesswork (Roboto + Roboto Slab)
  • Pairing failures — two near-identical faces, both faces competing for attention, one face overwhelming the other

Product applications:

Context Application Example
Editorial site Serif headlines + sans body Playfair Display + Source Sans Pro
Documentation Monospace code + sans prose from one family IBM Plex Mono + IBM Plex Sans
Minimal brand Single family with weight variation Inter at varying weights and sizes

Copy patterns:

/* Classic serif + sans-serif pairing */
h1, h2, h3 { font-family: 'Playfair Display', Georgia, serif; }
body { font-family: 'Source Sans Pro', -apple-system, sans-serif; }

See: references/pairing-strategies.md when picking a second face — proven combinations, the contrast-type table, and same-designer/superfamily shortcuts.

5. Typographic Measurements

Core concept: Three measurements — font size, line length, and line height — form the foundation of comfortable reading. Getting these right matters more than typeface choice.

Why it works: These measurements govern how the eye tracks across and down text: optimal line length matches the saccade pattern, adequate line height prevents the eye from jumping to the wrong line on the return sweep, and sufficient size makes letterforms recognizable on screen.

Key insights:

  • Body size — 16px minimum; err larger (18px) for reading-heavy sites; mobile users hold phones farther than designers assume
  • Line length (measure) — 45-75 characters ideal, 66 optimal; enforce with ch units or max-width
  • Line height — 1.4-1.8 for body; longer lines need more; headlines need tighter (1.1-1.25)
  • Heading scale — consistent ratio (1.2-1.5) between levels creates hierarchy without extremes

Product applications:

Context Application Example
Blog / article 65ch max-width, 1.6 line height .prose { max-width: 65ch; line-height: 1.6; }
Dashboard Tighter line height for dense data line-height: 1.3; for table cells and labels
Landing page Generous sizing for scanability font-size: 1.25rem; line-height: 1.7;

Copy patterns:

.prose {
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  line-height: 1.6;
  max-width: 65ch;
}
/* Line height by context */
h1, h2 { line-height: 1.1; }      /* headlines: 1.1-1.25 */
.ui-text { line-height: 1.35; }   /* UI: 1.3-1.4 */
.body-text { line-height: 1.6; }  /* body: 1.5-1.7 */

See: references/responsive-typography.md when writing the clamp() formulas — how to derive min/preferred/max and viewport-based measurement strategies.

6. Building Type Hierarchies

Core concept: Hierarchy tells readers what matters most. Create distinction through controlled variation in size, weight, and color — but don't pull all three levers at once.

Why it works: Deliberate, consistent differences between levels let readers grasp page structure at a glance; without hierarchy everything competes and nothing wins.

Key insights:

  • Three levers — size, weight, color; vary one or two between adjacent levels, never all three
  • The squint test — squinting at a page should still reveal the hierarchy
  • Consistent scale — a modular ratio (1.2-1.5) between heading levels creates rhythm; arbitrary sizes create noise
  • Don't skip levels — jumping H1 to H3 breaks the reader's mental model

Product applications:

Context Application Example
Content page Size + weight across 4-5 levels H1 2.5rem/700, H2 1.75rem/600, Body 1rem/400
Dashboard Weight + color for data vs. labels Bold #111 values, regular #666 labels
Form UI Subtle weight shift for labels Label: 600 weight, input: 400 weight

Copy patterns:

h1 { font-size: clamp(2rem, 1.5rem + 2vw, 3rem); font-weight: 700; color: #111; }
h2 { font-size: clamp(1.5rem, 1.25rem + 1vw, 2rem); font-weight: 600; color: #111; }
body { font-size: 1rem; font-weight: 400; color: #333; }
.secondary { font-size: 0.875rem; color: #666; }
/* Headings: more space above than below */
h1, h2, h3 { margin: 1.5em 0 0.5em; line-height: 1.2; }

Ethical boundary: Don't bury fees, disclaimers, or opt-outs in small or low-contrast type to demote what users need to see — hierarchy that hides material information weaponizes typography against the reader.

See: references/css-implementation.md when implementing the CSS — full hierarchy patterns, @font-face loading, font-variation-settings axes, and subsetting with pyftsubset.

7. Responsive Typography and Web Font Performance

Core concept: Type must adapt to screens, and web fonts must load efficiently. Fluid typography with clamp() eliminates breakpoint jumps; strategic font loading prevents layout shift and slow renders.

Why it works: A fixed font size cannot serve both a 320px phone and a 1440px desktop. Web fonts are render-blocking by default — unoptimized loading causes Flash of Invisible Text (FOIT) or Flash of Unstyled Text (FOUT).

Key insights:

  • Fluid typography — clamp(min, preferred, max) scales smoothly between viewports, no media queries needed for type
  • Breakpoint adjustments — mobile needs slightly larger body (17-18px) and a tighter heading scale; desktop can push display sizes while keeping line-length limits
  • Loading strategy — font-display: swap shows fallback text immediately; preload critical fonts; subset to needed characters
  • Performance budget — under 200KB total font payload; prefer WOFF2; a variable font can replace 4-6 static weight files

Product applications:

Context Application Example
Content site Fluid sizes with clamp() font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem)
E-commerce Preload hero font, lazy-load secondary weights <link rel="preload" href="font.woff2" as="font">
Global product Subset per language to cut payload Latin subset for English, CJK subset for Asian pages

Copy patterns:

h1 { font-size: clamp(2rem, 1.5rem + 2vw, 3.5rem); }

@font-face {
  font-family: 'Custom Font';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: swap;
  unicode-range: U+0000-00FF; /* Latin subset */
}
/* In <head>: <link rel="preload" href="/fonts/custom.woff2" as="font" type="font/woff2" crossorigin> */

Ethical boundary: Don't optimize users out — subsetting that drops characters non-English readers need, or removing italic/bold weights needed for emphasis, trades inclusivity for speed.

Common Mistakes

Mistake Why It Fails Fix
Text feels cramped Tight line height fatigues readers Increase line-height to 1.6+; add paragraph spacing
Lines too long Beyond 75 chars the eye loses the return sweep max-width: 65ch on text containers
Headings look disconnected Excess space above breaks association with content Reduce space above heading; keep space below
Text looks blurry Font-smoothing or subpixel rendering issues Check font-smoothing; try different weight; increase size
Fonts loading slowly Unoptimized files block rendering Subset; font-display: swap; preload critical fonts
Body text too small Phones held farther than assumed; strains older eyes Increase to 18px; test at real distance
Hierarchy is unclear Insufficient contrast between levels Increase size/weight differences
Typefaces clash Pairing without clear contrast creates tension One family, or ensure structural contrast (serif + sans)
Lorem ipsum testing Dummy text hides rhythm and frequency problems Test with real, representative content

Quick Diagnostic

Question If No Action
Is body text 16px or larger? Too small for comfortable reading At least 16px; prefer 18px for reading-heavy pages
Is line length under 75 characters? Eye loses position on return sweep max-width: 65ch on prose containers
Is line height 1.4+ for body? Lines feel cramped, reading slows Increase to 1.5-1.7
Is there clear contrast between type levels? Hierarchy invisible, scanning fails Increase size or weight differences
Tested at actual sizes on real screens? Rendering surprises in production Test every use size on target devices
Is total font payload under 200KB? Slow loading hurts UX and SEO Subset, WOFF2, consider variable fonts
Are fallback fonts specified? FOIT leaves blank text System fallbacks in every font-family
Does the page work at 200% zoom? Accessibility failure for low vision Fix overflow and truncation at 200%
Are headings free of orphaned words? Trailing words look unfinished text-wrap: balance or manual breaks
Are links visually distinct? Users can't find interactive elements Color and/or underline distinction

Further Reading

About the Author

Jason Santa Maria is a graphic designer and educator who served as Creative Director at Typekit (now Adobe Fonts) and co-founded A Book Apart. He teaches at the School of Visual Arts in New York, and On Web Typography distills his bridge between traditional typographic craft and the realities of designing for screens.

Files (skills)
  • references
    • css-implementation.md 10.7 KB
      # CSS Typography Implementation
      
      Practical patterns for implementing web typography in CSS.
      
      
      ## Table of Contents
      1. [@font-face Fundamentals](#font-face-fundamentals)
      2. [font-display Strategies](#font-display-strategies)
      3. [Font Loading Optimization](#font-loading-optimization)
      4. [Variable Fonts](#variable-fonts)
      5. [System Font Stacks](#system-font-stacks)
      6. [Fallback Strategies](#fallback-strategies)
      7. [OpenType Features](#opentype-features)
      8. [Core Typography CSS](#core-typography-css)
      9. [Performance Checklist](#performance-checklist)
      10. [Quick Reference](#quick-reference)
      
      ---
      
      ## @font-face Fundamentals
      
      ### Basic Syntax
      
      ```css
      @font-face {
        font-family: 'Custom Font';
        src: url('/fonts/custom-regular.woff2') format('woff2'),
             url('/fonts/custom-regular.woff') format('woff');
        font-weight: 400;
        font-style: normal;
        font-display: swap;
      }
      
      @font-face {
        font-family: 'Custom Font';
        src: url('/fonts/custom-bold.woff2') format('woff2'),
             url('/fonts/custom-bold.woff') format('woff');
        font-weight: 700;
        font-style: normal;
        font-display: swap;
      }
      
      @font-face {
        font-family: 'Custom Font';
        src: url('/fonts/custom-italic.woff2') format('woff2'),
             url('/fonts/custom-italic.woff') format('woff');
        font-weight: 400;
        font-style: italic;
        font-display: swap;
      }
      ```
      
      ### Format Priority
      
      ```css
      src: url('font.woff2') format('woff2'),  /* Best compression, 97%+ support */
           url('font.woff') format('woff');     /* Fallback for older browsers */
      ```
      
      **Skip these formats:**
      - TTF/OTF - Larger files, no benefit for web
      - EOT - Only needed for IE8 (likely not your audience)
      - SVG fonts - Deprecated
      
      ## font-display Strategies
      
      Controls how text renders while fonts load:
      
      | Value | Behavior | Use When |
      |-------|----------|----------|
      | `swap` | Show fallback immediately, swap when loaded | Body text, readability critical |
      | `block` | Hide text briefly (~3s), then show fallback | Headlines where flash is jarring |
      | `fallback` | Brief block (~100ms), then fallback, optional swap | Balance of speed and stability |
      | `optional` | Brief block, may skip custom font on slow connections | Performance is top priority |
      | `auto` | Browser decides | Avoid - unpredictable |
      
      ### Recommended Approach
      
      ```css
      /* Body fonts: always swap - content must be readable */
      @font-face {
        font-family: 'Body Font';
        src: url('body.woff2') format('woff2');
        font-display: swap;
      }
      
      /* Display fonts: can block briefly */
      @font-face {
        font-family: 'Display Font';
        src: url('display.woff2') format('woff2');
        font-display: block;
      }
      ```
      
      ## Font Loading Optimization
      
      ### Preload Critical Fonts
      
      ```html
      <head>
        <!-- Preload most important fonts -->
        <link rel="preload" href="/fonts/body-regular.woff2" as="font" type="font/woff2" crossorigin>
        <link rel="preload" href="/fonts/body-bold.woff2" as="font" type="font/woff2" crossorigin>
      </head>
      ```
      
      **Only preload:**
      - Fonts visible above the fold
      - 2-3 maximum (more blocks other resources)
      - Most commonly used weights
      
      ### Reduce Font Files
      
      **Subset fonts** to include only needed characters:
      
      ```bash
      # Using pyftsubset (fonttools)
      pyftsubset font.ttf --output-file=font-subset.woff2 --flavor=woff2 \
        --layout-features='kern,liga' \
        --unicodes="U+0000-00FF,U+2000-206F"
      ```
      
      Common subsetting ranges:
      - `U+0000-00FF` - Basic Latin
      - `U+0100-017F` - Latin Extended-A (Western European)
      - `U+2000-206F` - General punctuation
      
      **Online tools:**
      - [Transfonter](https://transfonter.org/)
      - [Fonttools](https://github.com/fonttools/fonttools)
      - [Everything Fonts](https://everythingfonts.com/subsetter)
      
      ### Load Weights Strategically
      
      ```css
      /* Load only what you use */
      /* If you only use 400 and 700, don't load 300, 500, 600 */
      
      @font-face {
        font-family: 'Custom Font';
        src: url('custom-400.woff2') format('woff2');
        font-weight: 400;
      }
      
      @font-face {
        font-family: 'Custom Font';
        src: url('custom-700.woff2') format('woff2');
        font-weight: 700;
      }
      ```
      
      ## Variable Fonts
      
      Single file containing multiple weights/widths/styles.
      
      ### Basic Variable Font Setup
      
      ```css
      @font-face {
        font-family: 'Variable Font';
        src: url('variable.woff2') format('woff2-variations');
        font-weight: 100 900;  /* Range of available weights */
        font-stretch: 75% 125%;  /* Range of available widths (if supported) */
        font-style: normal;
        font-display: swap;
      }
      
      /* Use any weight in the range */
      .light { font-weight: 300; }
      .regular { font-weight: 400; }
      .medium { font-weight: 500; }
      .semibold { font-weight: 600; }
      .bold { font-weight: 700; }
      ```
      
      ### Variable Font Axes
      
      ```css
      /* Common axes */
      .text {
        font-variation-settings:
          'wght' 450,   /* Weight */
          'wdth' 100,   /* Width */
          'slnt' -12,   /* Slant */
          'ital' 1;     /* Italic */
      }
      
      /* Prefer standard properties when available */
      .text {
        font-weight: 450;
        font-stretch: 100%;
        font-style: oblique 12deg;
      }
      ```
      
      ### Variable Font Benefits
      
      | Advantage | Impact |
      |-----------|--------|
      | Smaller total size | One 80KB file vs. four 40KB files |
      | Granular control | Use weight 450 instead of just 400 or 500 |
      | Responsive weight | Adjust weight fluidly with viewport |
      | Animation | Smooth weight/width transitions |
      
      ### Popular Variable Fonts
      
      | Font | Axes | Good For |
      |------|------|----------|
      | Inter | weight, slant | UI, body text |
      | Roboto Flex | weight, width, slant | Versatile, Google ecosystem |
      | Source Sans 3 | weight | Body text, UI |
      | Recursive | weight, slant, MONO, CASL | Code, UI, versatile |
      | Fraunces | weight, SOFT, WONK | Display, editorial |
      
      ## System Font Stacks
      
      Fast loading, native feel, no font files needed.
      
      ### Modern System Stack
      
      ```css
      body {
        font-family:
          -apple-system,           /* Safari on macOS and iOS */
          BlinkMacSystemFont,      /* Chrome on macOS */
          'Segoe UI',              /* Windows */
          Roboto,                  /* Android, Chrome OS */
          'Helvetica Neue',        /* Older macOS */
          Arial,                   /* Fallback */
          sans-serif;              /* Generic fallback */
      }
      ```
      
      ### System UI Keyword
      
      ```css
      /* Modern browsers support this shortcut */
      body {
        font-family: system-ui, sans-serif;
      }
      ```
      
      ### Monospace System Stack
      
      ```css
      code, pre {
        font-family:
          ui-monospace,              /* San Francisco Mono on macOS */
          'Cascadia Code',           /* Windows Terminal */
          'Source Code Pro',         /* Popular fallback */
          Menlo,                     /* macOS */
          Consolas,                  /* Windows */
          monospace;
      }
      ```
      
      ## Fallback Strategies
      
      ### Matching Fallbacks
      
      Choose fallbacks with similar metrics to minimize layout shift:
      
      ```css
      /* If custom font has tall x-height, don't fallback to one that doesn't */
      body {
        font-family: 'Inter', 'Helvetica Neue', Arial, sans-serif;
      }
      
      /* Georgia and Times have similar metrics */
      body {
        font-family: 'Source Serif Pro', Georgia, 'Times New Roman', serif;
      }
      ```
      
      ### Adjusting Fallback Metrics
      
      ```css
      /* Adjust fallback to match custom font metrics */
      @font-face {
        font-family: 'Adjusted Arial';
        src: local('Arial');
        size-adjust: 105%;        /* Scale to match custom font */
        ascent-override: 90%;     /* Adjust ascender */
        descent-override: 20%;    /* Adjust descender */
        line-gap-override: 0%;    /* Adjust line gap */
      }
      
      body {
        font-family: 'Custom Font', 'Adjusted Arial', sans-serif;
      }
      ```
      
      ## OpenType Features
      
      ### Common Features
      
      ```css
      /* Ligatures */
      .prose {
        font-feature-settings: "liga" 1, "clig" 1;  /* Standard ligatures */
      }
      
      /* Disable ligatures in code */
      code {
        font-feature-settings: "liga" 0;
      }
      
      /* Figure styles */
      .body-text {
        font-feature-settings: "onum" 1;  /* Oldstyle figures */
      }
      
      .table {
        font-feature-settings: "lnum" 1, "tnum" 1;  /* Tabular lining */
      }
      
      /* Small caps */
      .acronym {
        font-feature-settings: "smcp" 1;
        /* Or use the property directly: */
        font-variant-caps: small-caps;
      }
      
      /* Fractions */
      .recipe {
        font-feature-settings: "frac" 1;  /* 1/2 becomes proper fraction */
      }
      ```
      
      ### Feature Detection
      
      ```css
      @supports (font-variant-numeric: tabular-nums) {
        .table {
          font-variant-numeric: tabular-nums lining-nums;
        }
      }
      ```
      
      ## Core Typography CSS
      
      ### Base Setup
      
      ```css
      :root {
        /* Type scale */
        --text-xs: 0.75rem;
        --text-sm: 0.875rem;
        --text-base: 1rem;
        --text-lg: 1.125rem;
        --text-xl: 1.25rem;
        --text-2xl: 1.5rem;
        --text-3xl: 2rem;
        --text-4xl: 2.5rem;
      
        /* Line heights */
        --leading-tight: 1.2;
        --leading-snug: 1.4;
        --leading-normal: 1.6;
        --leading-relaxed: 1.8;
      
        /* Spacing */
        --measure: 65ch;
      }
      
      body {
        font-family: 'Source Sans Pro', system-ui, sans-serif;
        font-size: var(--text-base);
        line-height: var(--leading-normal);
        color: #333;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
      }
      ```
      
      ### Heading Styles
      
      ```css
      h1, h2, h3, h4, h5, h6 {
        font-family: 'Source Serif Pro', Georgia, serif;
        line-height: var(--leading-tight);
        margin-top: 1.5em;
        margin-bottom: 0.5em;
      }
      
      h1 { font-size: var(--text-4xl); }
      h2 { font-size: var(--text-3xl); }
      h3 { font-size: var(--text-2xl); }
      h4 { font-size: var(--text-xl); }
      h5 { font-size: var(--text-lg); }
      h6 { font-size: var(--text-base); }
      
      /* First heading shouldn't have top margin */
      h1:first-child,
      h2:first-child,
      h3:first-child {
        margin-top: 0;
      }
      ```
      
      ### Paragraph and Prose
      
      ```css
      p {
        margin-bottom: 1em;
      }
      
      .prose {
        max-width: var(--measure);
      }
      
      .prose p + p {
        margin-top: 1.5em;
      }
      
      .prose ul,
      .prose ol {
        padding-left: 1.5em;
        margin-bottom: 1em;
      }
      
      .prose li {
        margin-bottom: 0.5em;
      }
      
      .prose blockquote {
        border-left: 4px solid #e5e5e5;
        padding-left: 1em;
        margin-left: 0;
        font-style: italic;
      }
      ```
      
      ### Links and Emphasis
      
      ```css
      a {
        color: #0066cc;
        text-decoration: underline;
        text-underline-offset: 2px;
      }
      
      a:hover {
        color: #004499;
      }
      
      strong, b {
        font-weight: 600;
      }
      
      em, i {
        font-style: italic;
      }
      
      small {
        font-size: var(--text-sm);
      }
      ```
      
      ## Performance Checklist
      
      Before shipping:
      
      - [ ] Fonts in WOFF2 format
      - [ ] Total font payload < 200KB
      - [ ] Critical fonts preloaded
      - [ ] font-display set appropriately
      - [ ] Unused weights removed
      - [ ] Fonts subsetted if possible
      - [ ] Fallback fonts have similar metrics
      - [ ] No layout shift from font loading
      
      ## Quick Reference
      
      ### Font Weight Values
      
      | Value | Common Name |
      |-------|-------------|
      | 100 | Thin |
      | 200 | Extra Light |
      | 300 | Light |
      | 400 | Regular |
      | 500 | Medium |
      | 600 | Semi Bold |
      | 700 | Bold |
      | 800 | Extra Bold |
      | 900 | Black |
      
      ### Useful Units
      
      | Unit | Use For |
      |------|---------|
      | rem | Font sizes (scales with root) |
      | em | Spacing relative to current font |
      | ch | Line length (character width) |
      | vw | Fluid sizing in clamp() |
      | % | Relative to parent |
      
      ### Browser Support
      
      | Feature | Support |
      |---------|---------|
      | WOFF2 | 97%+ |
      | Variable fonts | 95%+ |
      | font-display | 95%+ |
      | clamp() | 95%+ |
      | font-variant-* | 90%+ |
      
    • evaluating-typefaces.md 8.2 KB
      # Evaluating Typefaces
      
      A systematic approach to assessing whether a typeface will work for your project.
      
      ## Quality Indicators
      
      ### Visual Consistency
      
      A well-designed typeface has consistent visual rhythm:
      
      | Check | What to Look For |
      |-------|------------------|
      | **Stroke weight** | Consistent thickness throughout the alphabet |
      | **Color** | Even darkness when viewing a text block |
      | **Proportion** | Characters relate harmoniously to each other |
      | **Curves** | Smooth, intentional curves without awkward joints |
      
      **Quick test:** Set a paragraph and squint. Good typefaces appear as an even gray; poor ones show dark spots or inconsistent density.
      
      ### Technical Quality
      
      | Criterion | Signs of Quality | Signs of Problems |
      |-----------|------------------|-------------------|
      | **Kerning** | Even spacing across character pairs | Awkward gaps (AV, To, Ty, ff) |
      | **Hinting** | Crisp rendering at small sizes | Blurry or uneven at 14-16px |
      | **Spacing** | Consistent rhythm without adjustment | Needs manual letter-spacing fixes |
      | **Rendering** | Clean on multiple browsers/OS | Looks different across platforms |
      
      ### Character Set Completeness
      
      **Minimum requirements:**
      - Full ASCII (A-Z, a-z, 0-9, basic punctuation)
      - Common accented characters (é, ñ, ü, etc.)
      - Proper typographic quotes ("" '' vs "" '')
      - Em dash (—), en dash (–), minus (−)
      - Euro (€), pound (£), other needed currency
      
      **Better:**
      - Full Latin Extended character set
      - Smart quotes and proper apostrophes
      - Multiple figure styles (oldstyle, lining, tabular)
      - True small caps
      - Ligatures (fi, fl, ff, ffi)
      
      **Check character support:** [caniuse.com's font feature tests](https://wakamaifondue.com/) for OpenType features.
      
      ## Structural Analysis
      
      ### X-Height Assessment
      
      Higher x-height improves screen readability at small sizes.
      
      ```
      Typeface A:   The quick brown fox    (large x-height)
      Typeface B:   The quick brown fox    (small x-height)
      
      At same point size, A appears larger and more readable.
      ```
      
      **When to prefer larger x-height:**
      - Body text on screens
      - Small sizes (14-16px)
      - UI text
      - Mobile interfaces
      
      **When smaller x-height works:**
      - Large display text
      - Headlines
      - Print (higher resolution)
      - When elegance matters more than readability
      
      ### Counter and Aperture Openness
      
      Open counters and apertures improve legibility, especially on screens:
      
      ```
      Open:    a e c s g    (clear, distinct)
      Closed:  a e c s g    (can fill in at small sizes)
      ```
      
      Check these characters specifically:
      - **a** - How open is the counter?
      - **e** - How large is the aperture?
      - **c** - Wide or closed opening?
      - **s** - Open curves or tight?
      
      ### Stroke Contrast
      
      | Contrast | Screen Performance | Personality |
      |----------|-------------------|-------------|
      | Low/None | Excellent - consistent at all sizes | Modern, neutral, sturdy |
      | Medium | Good - works for most body text | Classic, refined |
      | High | Poor at small sizes - thin strokes disappear | Elegant, delicate, display-only |
      
      **Rule:** High-contrast typefaces (Bodoni, Didot) are headlines-only on screens.
      
      ### Distinguishable Characters
      
      Critical for legibility. Test these easily-confused sets:
      
      | Set | What to Check |
      |-----|---------------|
      | **Il1\|** | Can you distinguish capital I, lowercase l, numeral 1, pipe? |
      | **O0** | Is capital O distinct from zero? |
      | **rn vs m** | Do "rn" together look like "m"? |
      | **cl vs d** | At small sizes, could these be confused? |
      | **5S** | Distinct enough in both cases? |
      | **6b, 9q** | Clear differentiation? |
      
      Some typefaces add distinguishing features:
      - Serifs on capital I
      - Slashed or dotted zero
      - Curved tail on lowercase l
      - Open counter on 4
      
      ## Testing Protocol
      
      ### 1. Test at Actual Sizes
      
      Don't evaluate at 36px if you'll use it at 16px. Common sizes to test:
      
      | Use Case | Test Sizes |
      |----------|------------|
      | Body text | 14px, 16px, 18px |
      | Secondary text | 12px, 13px |
      | Headlines | 24px, 32px, 48px |
      | UI text | 13px, 14px, 15px |
      
      ### 2. Test with Real Content
      
      Lorem ipsum hides problems. Use:
      - Actual content from your project
      - Text with numbers (to check figure styles)
      - Text with punctuation (em dashes, quotes)
      - Text with special characters your audience needs
      
      ### 3. Test in Context
      
      - On actual target devices (phone, tablet, desktop)
      - In actual browsers (Chrome, Safari, Firefox)
      - On different operating systems (Windows renders differently than Mac)
      - With your actual background colors
      
      ### 4. Test at Scale
      
      If possible, set several paragraphs. Single sentences don't reveal:
      - Text color (overall density)
      - How the typeface "feels" to read
      - Any rhythm issues
      - Line-to-line consistency
      
      ## Practical Evaluation Checklist
      
      ### Body Text Candidates
      
      - [ ] Readable at 16px without strain
      - [ ] Even color in text blocks (squint test)
      - [ ] Distinguishable Il1 and O0
      - [ ] Open counters (check lowercase a, e, c)
      - [ ] Complete character set for your languages
      - [ ] Regular + Bold + Italics available
      - [ ] Good hinting (crisp on Windows)
      - [ ] Reasonable file size (< 50KB per weight)
      - [ ] Clear at 200% browser zoom
      - [ ] Renders consistently across browsers
      
      ### Headline Candidates
      
      - [ ] Strong personality at large sizes
      - [ ] Maintains character down to ~24px
      - [ ] Works with your body typeface
      - [ ] At least 2-3 weights available
      - [ ] File size acceptable for what's loaded
      - [ ] Distinct from body text (provides contrast)
      
      ### UI Text Candidates
      
      - [ ] Crystal clear at 13-14px
      - [ ] Compact but readable
      - [ ] Multiple weights for hierarchy
      - [ ] Numbers align well (tabular figures available)
      - [ ] Good uppercase (for buttons, labels)
      - [ ] Works with icons at same size
      
      ## Free vs. Paid Considerations
      
      ### Free Fonts (Google Fonts, Font Squirrel, etc.)
      
      **Advantages:**
      - No cost
      - Easy implementation
      - Often good quality (Google Fonts are curated)
      
      **Considerations:**
      - May be overused (Roboto, Open Sans everywhere)
      - Sometimes incomplete character sets
      - Variable quality in hinting/kerning
      - May lack advanced OpenType features
      
      **Quality free options:**
      - Inter (UI, body)
      - Source Sans/Serif Pro (body, editorial)
      - IBM Plex family (tech, corporate)
      - Literata (reading)
      - Atkinson Hyperlegible (accessibility)
      
      ### Paid Fonts
      
      **Advantages:**
      - Often superior craftsmanship
      - More distinctive options
      - Better support and updates
      - Complete feature sets
      - Professional licensing terms
      
      **Considerations:**
      - Cost (though often reasonable per-project)
      - Licensing complexity for web use
      - Need to self-host or use a service
      
      **When to pay:**
      - Brand differentiation matters
      - Long-form reading is primary use
      - You need specific OpenType features
      - Project budget allows
      
      ## Web Font Performance
      
      File size directly impacts load time. Budget guidelines:
      
      | Quality | Total Font Budget |
      |---------|-------------------|
      | Fast | < 100KB |
      | Acceptable | 100-200KB |
      | Heavy | > 200KB (needs justification) |
      
      ### Optimization Strategies
      
      1. **Subset:** Include only characters you need
      2. **Choose wisely:** 2 weights instead of 5
      3. **WOFF2 format:** Smallest file size
      4. **Variable fonts:** One file, many weights
      
      ### Format Priority
      
      ```css
      @font-face {
        font-family: 'Custom';
        src: url('font.woff2') format('woff2'),  /* Modern browsers */
             url('font.woff') format('woff');     /* Older browsers */
      }
      ```
      
      WOFF2 has best compression and near-universal support. Skip TTF/OTF for web.
      
      ## Red Flags
      
      Avoid typefaces with these issues:
      
      | Red Flag | Why It Matters |
      |----------|----------------|
      | No hinting | Will render poorly on Windows |
      | Very thin weights | Disappear at small sizes |
      | Incomplete kerning | Requires manual spacing fixes |
      | Missing basic characters | Will show boxes or fallback |
      | Poor screen rendering | May look fine in samples, not in use |
      | Unusual licensing | Can cause legal issues |
      | "Inspired by" knock-offs | Lower quality, potential legal issues |
      | Only one weight | Limits hierarchy options |
      
      ## Quick Comparison Method
      
      When choosing between finalists:
      
      1. Set identical paragraph with each
      2. View at 100%, 150%, and 50% zoom
      3. Check on phone and desktop
      4. Read a full paragraph with each (actually read it)
      5. Look away, then look back—which is more inviting?
      6. Check file sizes and loading impact
      7. Verify all needed characters exist
      
      Trust your reading experience. If something feels "off" while reading, it probably is, even if you can't articulate why.
      
    • pairing-strategies.md 8.2 KB
      # Typeface Pairing Strategies
      
      How to successfully combine typefaces—and when to use just one.
      
      ## The Fundamental Rule
      
      **One to two typefaces maximum.** Using more requires exceptional skill and specific justification. When uncertain, one typeface with weight/style variation is safer than a poor pairing.
      
      ## The Contrast Principle
      
      Successful pairings have **clear, intentional contrast**. Faces should be obviously different, not confusingly similar.
      
      **This works:**
      ```
      Serif headline + Sans-serif body
      → Clear structural contrast
      ```
      
      **This doesn't:**
      ```
      Helvetica headline + Arial body
      → Too similar, looks like a mistake
      ```
      
      ### Types of Contrast
      
      | Contrast Type | How It Works | Example |
      |---------------|--------------|---------|
      | **Structure** | Serif vs. sans-serif | Playfair Display + Source Sans |
      | **Weight** | Light vs. regular/bold | Thin headline + regular body |
      | **Width** | Condensed vs. normal | Oswald (condensed) + Merriweather |
      | **Era** | Historical vs. modern | Garamond + Futura |
      | **Mood** | Formal vs. casual | Bodoni + Proxima Nova |
      
      ## Pairing Strategies
      
      ### 1. Serif + Sans-Serif (The Classic)
      
      The most reliable approach. Structural contrast is automatic.
      
      **Serif headlines + Sans body:**
      - Traditional, editorial feel
      - Headline has personality, body is neutral
      - Works for: news, magazines, blogs
      
      **Sans headlines + Serif body:**
      - Modern but readable
      - Clean headers, comfortable reading
      - Works for: books, longform, documentation
      
      | Serif | Sans-Serif | Character |
      |-------|------------|-----------|
      | Playfair Display | Source Sans Pro | Elegant editorial |
      | Lora | Inter | Warm modern |
      | Merriweather | Open Sans | Friendly, readable |
      | Freight Text | Freight Sans | Matched DNA |
      | Georgia | Verdana | Web classics |
      | PT Serif | PT Sans | Designed together |
      
      ### 2. Same Designer Harmony
      
      Typefaces by one designer often share underlying proportions and philosophy, creating natural harmony.
      
      | Designer | Faces | Notes |
      |----------|-------|-------|
      | Erik Spiekermann | FF Meta + FF Meta Serif | Near-perfect pairing |
      | Matthew Carter | Georgia + Verdana | Designed for screens together |
      | Mark Simonson | Proxima Nova + Proxima Serif | Superfamily |
      | ParaType | PT Sans + PT Serif | Free, designed as pair |
      | Christian Schwartz | Graphik + Produkt | Contemporary pair |
      
      ### 3. Superfamilies
      
      Typefaces designed from the start to work together. Safest pairing option.
      
      | Superfamily | Includes | Best For |
      |-------------|----------|----------|
      | **Roboto** | Sans, Serif, Slab, Condensed, Mono | Google ecosystem, apps |
      | **IBM Plex** | Sans, Serif, Mono | Tech, documentation |
      | **Source** | Sans Pro, Serif Pro, Code Pro | Versatile, readable |
      | **Noto** | Sans, Serif (many scripts) | Internationalization |
      | **FF Meta** | Sans, Serif | Corporate, editorial |
      
      ### 4. Same Era Pairing
      
      Typefaces from the same historical period share proportional assumptions.
      
      | Era | Characteristics | Example Pairing |
      |-----|-----------------|-----------------|
      | **Renaissance** | Old-style serifs, humanist sans | Garamond + Gill Sans |
      | **Neoclassical** | Transitional serifs, rational sans | Baskerville + Univers |
      | **Victorian** | Slab serifs, grotesques | Clarendon + Franklin Gothic |
      | **Modernist** | Geometric sans, high-contrast serif | Futura + Bodoni |
      | **Contemporary** | Humanist sans, contemporary serif | Frutiger + Charter |
      
      ### 5. Contrast by Role
      
      Assign different jobs to create natural separation:
      
      | Role | Face Type | Purpose |
      |------|-----------|---------|
      | Headlines | Display, personality | Catch attention, set tone |
      | Body | Workhorse, neutral | Comfortable reading |
      | UI/Navigation | Compact, clear | Functional, small sizes |
      | Captions | Smaller optical size | Secondary information |
      
      ## Proven Pairings
      
      ### Editorial/Publishing
      
      | Headline | Body | Vibe |
      |----------|------|------|
      | Playfair Display | Source Serif Pro | Classic elegance |
      | Merriweather | Merriweather Sans | Unified, friendly |
      | Cormorant Garamond | Proza Libre | Literary, refined |
      | Libre Baskerville | Source Sans Pro | Traditional news |
      
      ### Tech/Modern
      
      | Headline | Body | Vibe |
      |----------|------|------|
      | Inter | Inter | One face, weight variation |
      | Poppins | IBM Plex Sans | Geometric, clean |
      | Manrope | Inter | Contemporary startup |
      | Space Grotesk | IBM Plex Mono | Developer, technical |
      
      ### Warm/Friendly
      
      | Headline | Body | Vibe |
      |----------|------|------|
      | Lora | Open Sans | Approachable editorial |
      | Nunito | Source Sans Pro | Rounded, friendly |
      | Fraunces | Commissioner | Playful yet readable |
      | DM Serif Display | DM Sans | Google pairing |
      
      ### Corporate/Professional
      
      | Headline | Body | Vibe |
      |----------|------|------|
      | Montserrat | Open Sans | Clean, neutral |
      | Raleway | Roboto | Geometric modern |
      | Work Sans | Source Serif Pro | Business editorial |
      | Outfit | Lora | Contemporary warmth |
      
      ## When One Typeface Is Enough
      
      A single well-chosen typeface often works better than a poor pairing:
      
      **Use one typeface when:**
      - The family has enough weights (light through bold)
      - You need simplicity and consistency
      - The typeface works at all needed sizes
      - Brand identity favors minimalism
      - You're not confident in pairing
      
      **Create variety within one face:**
      - Weight contrast (Light headlines, Regular body)
      - Size contrast (Large vs. small)
      - Case variation (ALL CAPS for labels)
      - Color variation (Dark vs. gray)
      - Style variation (Italic for emphasis)
      
      **Great single-family choices:**
      - Inter (9 weights, highly readable)
      - Source Sans Pro (6 weights, workhorse)
      - Roboto (extensive family)
      - IBM Plex Sans (complete, professional)
      - Nunito (friendly, many weights)
      
      ## Pairing Mistakes to Avoid
      
      ### Too Similar
      
      ```
      ❌ Helvetica + Arial
      ❌ Garamond + Times New Roman
      ❌ Open Sans + Source Sans Pro
      
      → Looks like an accident, not a choice
      ```
      
      If viewers can't instantly tell faces apart, choose more contrast or use one.
      
      ### Competing Personality
      
      ```
      ❌ Papyrus + Comic Sans
      ❌ Lobster + Pacifico
      ❌ Impact + Bebas Neue
      
      → Both demand attention, neither wins
      ```
      
      One face can have personality; the other should be neutral.
      
      ### Era Clash
      
      ```
      ⚠️ Bodoni (1798) + Futura (1927)
      ⚠️ Garamond (1530s) + Helvetica (1957)
      
      → Can work with intent, but often feels "off"
      ```
      
      Mixing eras requires understanding why you're doing it.
      
      ### Weight Imbalance
      
      ```
      ❌ Ultra-bold headline + Ultra-light body
      ❌ Thin display + Heavy body text
      
      → One overwhelms the other
      ```
      
      Headline should be heavier than body, but proportionally.
      
      ### Script Overuse
      
      ```
      ❌ Script headline + Script subhead + Script accent
      ❌ Script anywhere near body text
      
      → Scripts are accents only, never primary
      ```
      
      ## Testing Your Pairing
      
      ### Quick Tests
      
      1. **The Squint Test:** Blur your vision. Is hierarchy clear?
      2. **The Zoom Test:** View at 50% and 200%. Does it hold?
      3. **The Read Test:** Actually read a paragraph. Comfortable?
      4. **The Swap Test:** Reverse headline/body. Does original still feel right?
      5. **The Context Test:** View in actual design, not just a type specimen.
      
      ### Red Flags While Testing
      
      - You have to explain why the pairing works
      - Characters look mismatched at same size
      - One face consistently draws your eye (unless it should)
      - The pairing feels "trendy" rather than appropriate
      - You're not sure which face to use where
      
      ### Signs of a Good Pairing
      
      - Immediately feels "right" without explanation
      - Clear contrast but not jarring
      - Each face has a defined job
      - Works at multiple sizes
      - Maintains hierarchy across contexts
      - Feels intentional, not accidental
      
      ## Process for Finding Pairs
      
      1. **Start with body text:** Choose your workhorse first. It carries the load.
      2. **Define needed contrast:** What kind? Structural? Weight? Era?
      3. **Test candidates:** Set actual headlines with actual body text.
      4. **Check the details:** Sizes, colors, spacing all working together?
      5. **Sleep on it:** Fresh eyes often reveal what excitement hid.
      
      ## Pairing Resources
      
      **For exploration:**
      - [Fontpair.co](https://fontpair.co) - Curated Google Font pairings
      - [Typewolf](https://www.typewolf.com) - Real-world examples
      - [FontJoy](https://fontjoy.com) - AI-assisted discovery
      
      **For validation:**
      - Google Fonts has a "Popular pairings" feature
      - Adobe Fonts suggests complements
      - Type foundry sites often show intended pairings
      
    • responsive-typography.md 9 KB
      # Responsive Typography
      
      Adapting type to screens, viewports, and reading contexts.
      
      
      ## Table of Contents
      1. [Core Principle](#core-principle)
      2. [The Problem with Fixed Sizes](#the-problem-with-fixed-sizes)
      3. [Fluid Typography with clamp()](#fluid-typography-with-clamp)
      4. [Complete Fluid Type System](#complete-fluid-type-system)
      5. [Responsive Line Length](#responsive-line-length)
      6. [Responsive Line Height](#responsive-line-height)
      7. [Breakpoint Strategy](#breakpoint-strategy)
      8. [Container Queries (Modern Approach)](#container-queries-modern-approach)
      9. [Reading Distance Considerations](#reading-distance-considerations)
      10. [Viewport Units Reference](#viewport-units-reference)
      11. [Practical Responsive Checklist](#practical-responsive-checklist)
      12. [Complete Example](#complete-example)
      13. [Tools and Resources](#tools-and-resources)
      
      ---
      
      ## Core Principle
      
      **Typography must respond to context.** A phone held at arm's length, a desktop monitor at desk distance, and a tablet on a couch all demand different typographic treatment.
      
      ## The Problem with Fixed Sizes
      
      Fixed pixel sizes create problems:
      
      ```css
      /* This doesn't adapt */
      h1 { font-size: 48px; }
      p { font-size: 16px; }
      ```
      
      - 48px headline overwhelms a 320px phone screen
      - 16px might be too small for users who hold phones far away
      - No relationship between text and available space
      
      ## Fluid Typography with clamp()
      
      The modern solution: `clamp()` creates type that scales smoothly between minimum and maximum values.
      
      ```css
      /* Syntax: clamp(minimum, preferred, maximum) */
      font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
      ```
      
      ### How clamp() Works
      
      | Part | Purpose | Example |
      |------|---------|---------|
      | Minimum | Floor - never smaller | 1rem (16px) |
      | Preferred | Scales with viewport | 0.9rem + 0.5vw |
      | Maximum | Ceiling - never larger | 1.25rem (20px) |
      
      The preferred value uses viewport units (vw) to scale, but clamp() prevents extremes.
      
      ### Body Text Formula
      
      ```css
      /* Scales from 16px to 20px between 320px and 1200px viewports */
      body {
        font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
      }
      ```
      
      Breakdown:
      - At 320px viewport: ~16px
      - At 768px viewport: ~18px
      - At 1200px+ viewport: 20px (capped)
      
      ### Heading Formulas
      
      ```css
      h1 {
        /* Scales from 32px to 56px */
        font-size: clamp(2rem, 1.5rem + 2vw, 3.5rem);
      }
      
      h2 {
        /* Scales from 24px to 40px */
        font-size: clamp(1.5rem, 1.25rem + 1.25vw, 2.5rem);
      }
      
      h3 {
        /* Scales from 20px to 28px */
        font-size: clamp(1.25rem, 1.1rem + 0.75vw, 1.75rem);
      }
      ```
      
      ### Generating clamp() Values
      
      **Formula for calculating:**
      ```
      preferred = minimum + (maximum - minimum) * ((100vw - minViewport) / (maxViewport - minViewport))
      ```
      
      **Simplified approach:**
      1. Pick min size at min viewport (e.g., 16px at 320px)
      2. Pick max size at max viewport (e.g., 20px at 1200px)
      3. Use a clamp generator or calculate the vw coefficient
      
      **Tools:**
      - [Utopia.fyi](https://utopia.fyi/type/calculator/) - Type scale generator
      - [clamp() Calculator](https://min-max-calculator.9elements.com/) - Interactive calculator
      
      ## Complete Fluid Type System
      
      ```css
      :root {
        /* Base scale using clamp() */
        --text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
        --text-sm: clamp(0.875rem, 0.8rem + 0.35vw, 1rem);
        --text-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
        --text-lg: clamp(1.125rem, 1rem + 0.6vw, 1.375rem);
        --text-xl: clamp(1.25rem, 1.1rem + 0.75vw, 1.625rem);
        --text-2xl: clamp(1.5rem, 1.25rem + 1.25vw, 2.25rem);
        --text-3xl: clamp(2rem, 1.5rem + 2vw, 3rem);
        --text-4xl: clamp(2.5rem, 1.75rem + 3vw, 4rem);
      }
      
      body { font-size: var(--text-base); }
      h1 { font-size: var(--text-4xl); }
      h2 { font-size: var(--text-3xl); }
      h3 { font-size: var(--text-2xl); }
      h4 { font-size: var(--text-xl); }
      .small { font-size: var(--text-sm); }
      .caption { font-size: var(--text-xs); }
      ```
      
      ## Responsive Line Length
      
      Line length must also adapt. 65 characters is ideal, but the method matters.
      
      ### Using ch Units
      
      ```css
      .prose {
        max-width: 65ch;  /* Approximately 65 characters */
      }
      ```
      
      **Note:** `ch` is based on the "0" character width. Actual character count varies by typeface.
      
      ### Responsive Constraints
      
      ```css
      .content {
        /* Fluid padding keeps text away from edges */
        padding-inline: clamp(1rem, 5vw, 3rem);
      
        /* Max-width prevents too-wide lines */
        max-width: min(65ch, 100% - 2rem);
      
        margin-inline: auto;
      }
      ```
      
      ## Responsive Line Height
      
      Wider lines need more line height. Adjust at breakpoints or fluidly:
      
      ```css
      /* Breakpoint approach */
      p {
        line-height: 1.5;
      }
      
      @media (min-width: 768px) {
        p {
          line-height: 1.6;
        }
      }
      
      @media (min-width: 1200px) {
        p {
          line-height: 1.7;
        }
      }
      ```
      
      ```css
      /* Fluid approach - ties line-height to container width */
      .prose {
        /* Wider = more line height */
        line-height: calc(1.5 + 0.2 * (100vw - 320px) / (1200 - 320));
      }
      ```
      
      ## Breakpoint Strategy
      
      ### Mobile First (Recommended)
      
      Start with mobile styles, add complexity for larger screens:
      
      ```css
      /* Mobile: base styles */
      body {
        font-size: 1rem;
        line-height: 1.5;
      }
      
      h1 {
        font-size: 2rem;
        line-height: 1.2;
      }
      
      /* Tablet */
      @media (min-width: 640px) {
        body {
          font-size: 1.0625rem;  /* 17px */
        }
      
        h1 {
          font-size: 2.5rem;
        }
      }
      
      /* Desktop */
      @media (min-width: 1024px) {
        body {
          font-size: 1.125rem;  /* 18px */
          line-height: 1.6;
        }
      
        h1 {
          font-size: 3rem;
        }
      }
      
      /* Large desktop */
      @media (min-width: 1440px) {
        body {
          font-size: 1.25rem;  /* 20px */
          line-height: 1.7;
        }
      }
      ```
      
      ### Key Breakpoints
      
      | Breakpoint | Typical Adjustments |
      |------------|---------------------|
      | 640px | Increase body text slightly; relax line length |
      | 768px | Tablet optimizations; two-column layouts possible |
      | 1024px | Desktop sizes; full hierarchy |
      | 1440px | Large screens; may need max-width constraints |
      
      ## Container Queries (Modern Approach)
      
      For component-based systems, container queries let type respond to component size, not viewport:
      
      ```css
      .card {
        container-type: inline-size;
      }
      
      .card-title {
        font-size: 1.25rem;
      }
      
      @container (min-width: 400px) {
        .card-title {
          font-size: 1.5rem;
        }
      }
      ```
      
      **Use case:** Same card component renders differently in a sidebar vs. main content area.
      
      ## Reading Distance Considerations
      
      Different devices = different reading distances:
      
      | Device | Typical Distance | Implication |
      |--------|------------------|-------------|
      | Phone | 10-12 inches | Can use slightly smaller text |
      | Tablet | 15-18 inches | Similar to desktop |
      | Desktop | 18-24 inches | Standard sizing works |
      | TV/Large display | 6+ feet | Much larger text needed |
      
      **For phones:** Don't automatically shrink text. Users often hold phones far away, and smaller text just means more squinting.
      
      ## Viewport Units Reference
      
      | Unit | Based On | Use Case |
      |------|----------|----------|
      | vw | Viewport width | Horizontal scaling |
      | vh | Viewport height | Vertical scaling (rarely for type) |
      | vmin | Smaller of vw/vh | Consistent scaling regardless of orientation |
      | vmax | Larger of vw/vh | Less common for type |
      | dvh | Dynamic viewport height | Accounts for mobile browser chrome |
      
      **Warning:** Pure viewport units (not in clamp) can get too small or too large:
      
      ```css
      /* Dangerous - no limits */
      font-size: 5vw;  /* Could be 16px or 96px */
      
      /* Safe - bounded */
      font-size: clamp(1rem, 5vw, 3rem);
      ```
      
      ## Practical Responsive Checklist
      
      Before launching:
      
      - [ ] Text readable at 320px viewport width
      - [ ] No horizontal scroll on mobile
      - [ ] Line length under 75 characters on desktop
      - [ ] Headings don't overwhelm on mobile
      - [ ] Body text at least 16px equivalent everywhere
      - [ ] Tested with browser zoom at 200%
      - [ ] Works in both portrait and landscape
      - [ ] Font loading doesn't cause major layout shift
      
      ## Complete Example
      
      ```css
      /* Responsive type system */
      :root {
        --font-body: 'Source Sans Pro', system-ui, sans-serif;
        --font-heading: 'Source Serif Pro', Georgia, serif;
      
        /* Fluid type scale */
        --text-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
        --text-lg: clamp(1.125rem, 1rem + 0.6vw, 1.5rem);
        --text-xl: clamp(1.25rem, 1rem + 1vw, 2rem);
        --text-2xl: clamp(1.5rem, 1rem + 1.5vw, 2.5rem);
        --text-3xl: clamp(2rem, 1rem + 2.5vw, 3.5rem);
      
        /* Fluid spacing */
        --space-prose: clamp(1rem, 5vw, 3rem);
      }
      
      body {
        font-family: var(--font-body);
        font-size: var(--text-base);
        line-height: 1.6;
      }
      
      h1, h2, h3 {
        font-family: var(--font-heading);
        line-height: 1.2;
      }
      
      h1 { font-size: var(--text-3xl); }
      h2 { font-size: var(--text-2xl); }
      h3 { font-size: var(--text-xl); }
      
      .prose {
        max-width: min(65ch, 100% - 2rem);
        padding-inline: var(--space-prose);
        margin-inline: auto;
      }
      
      /* Adjustments for wider viewports */
      @media (min-width: 1024px) {
        body {
          line-height: 1.7;
        }
      }
      ```
      
      ## Tools and Resources
      
      **Fluid type calculators:**
      - [Utopia.fyi](https://utopia.fyi/type/calculator/)
      - [Modern Fluid Typography Editor](https://modern-fluid-typography.vercel.app/)
      - [Fluid Type Scale Calculator](https://www.fluid-type-scale.com/)
      
      **Testing:**
      - Browser DevTools responsive mode
      - [Responsively App](https://responsively.app/) - Multi-device preview
      - Real devices when possible
      
    • typeface-anatomy.md 7.8 KB
      # Typeface Anatomy & Classification
      
      Understanding typeface structure helps you make informed decisions and communicate clearly about typography.
      
      ## Typeface vs. Font
      
      - **Typeface:** The design of the letters (e.g., Helvetica)
      - **Font:** A specific instance of a typeface (e.g., Helvetica Bold 14pt)
      
      Think of it like: typeface is the song, font is the MP3 file.
      
      ## Letterform Anatomy
      
      ### Vertical Measurements
      
      ```
      ┌─────────────────────────────────┐
      │                    Ascender     │ Cap line
      │         ┌───┐                   │
      │         │   │                   │ Ascender line
      │ ┌───┬───┤   │   │       │      │
      │ │   │   │   │───┤   ┌───┤      │ x-height
      │ │   │   │   │   │   │   │      │
      │ └───┴───┴───┘   └───┴───┘      │ Baseline
      │                     │          │
      │                     └──────────│ Descender line
      └─────────────────────────────────┘
        b   d   k   l       g   p   y
      ```
      
      | Term | Definition |
      |------|------------|
      | **Baseline** | Invisible line where letters sit |
      | **x-height** | Height of lowercase letters without ascenders/descenders (measured by lowercase "x") |
      | **Cap height** | Height of capital letters |
      | **Ascender** | Part of lowercase letters extending above x-height (b, d, f, h, k, l) |
      | **Descender** | Part of letters extending below baseline (g, j, p, q, y) |
      
      **Why x-height matters:** Larger x-height = better readability at small sizes. Two typefaces at the same point size can appear very different due to x-height variation.
      
      ### Horizontal Measurements
      
      | Term | Definition |
      |------|------------|
      | **Counter** | Enclosed or partially enclosed space within a letter (inside "o", "e", "a") |
      | **Aperture** | Opening into a counter (the gap in "c", "e", "s") |
      | **Bowl** | Curved stroke enclosing a counter (the round part of "b", "d", "p") |
      | **Set width** | Total horizontal space a character occupies, including sidebearings |
      
      **Open counters and apertures** improve legibility, especially at small sizes and on screens.
      
      ### Stroke Features
      
      | Term | Definition |
      |------|------------|
      | **Stroke** | The main lines forming a letter |
      | **Stem** | Main vertical stroke (the straight part of "d", "p", "l") |
      | **Crossbar** | Horizontal stroke (in "A", "H", "e") |
      | **Arm** | Horizontal or upward diagonal stroke that doesn't connect at one end ("K", "E") |
      | **Leg** | Downward diagonal stroke ("K", "R") |
      | **Shoulder** | Curved stroke of "h", "m", "n" |
      | **Tail** | Descending stroke, often decorative ("Q", "y") |
      | **Ear** | Small stroke projecting from lowercase "g" |
      | **Link/Neck** | Connection between the upper and lower bowls of two-story "g" |
      | **Spine** | Main curved stroke of "S" |
      
      ### Terminals and Serifs
      
      | Term | Definition |
      |------|------------|
      | **Serif** | Small projection at the end of strokes |
      | **Sans serif** | Without serifs ("sans" = without) |
      | **Terminal** | End of a stroke that doesn't have a serif |
      | **Ball terminal** | Circular shape at end of stroke (in some typefaces' "a", "c", "f") |
      | **Finial** | Tapered or curved terminal |
      | **Spur** | Small projection off a main stroke |
      | **Bracket** | Curved connection between serif and stem |
      
      ### Stroke Contrast
      
      **Stroke contrast** = difference between thick and thin strokes within a letter.
      
      | Contrast Level | Characteristics | Examples |
      |----------------|-----------------|----------|
      | High contrast | Dramatic thick/thin variation | Bodoni, Didot |
      | Medium contrast | Noticeable but moderate variation | Times New Roman, Baskerville |
      | Low contrast | Minimal thick/thin difference | Helvetica, most slab serifs |
      | Monolinear | No variation, uniform strokes | Futura, Gotham |
      
      **High contrast typefaces** can look elegant but may break down at small sizes where thin strokes disappear.
      
      ## Typeface Classification
      
      ### Serif Types
      
      | Category | Characteristics | Examples | Best For |
      |----------|-----------------|----------|----------|
      | **Old Style** | Low contrast, angled stress, bracketed serifs | Garamond, Palatino, Caslon | Long-form reading, books |
      | **Transitional** | Medium contrast, more vertical stress | Times New Roman, Baskerville, Georgia | Body text, editorial |
      | **Modern/Didone** | High contrast, vertical stress, thin flat serifs | Bodoni, Didot | Headlines, fashion, luxury |
      | **Slab Serif** | Low contrast, heavy rectangular serifs | Rockwell, Clarendon, Roboto Slab | Headlines, wayfinding |
      
      ### Sans-Serif Types
      
      | Category | Characteristics | Examples | Best For |
      |----------|-----------------|----------|----------|
      | **Grotesque** | Early sans designs, slight contrast, "quirky" | Akzidenz Grotesk, Franklin Gothic | Headlines, bold statements |
      | **Neo-grotesque** | Uniform strokes, neutral, little contrast | Helvetica, Arial, Univers | UI, neutral contexts |
      | **Humanist** | Calligraphic influence, open forms | Gill Sans, Frutiger, Open Sans | Body text, warm/friendly |
      | **Geometric** | Based on geometric shapes, circular "o" | Futura, Avenir, Gotham | Modern, clean, tech |
      
      ### Other Categories
      
      | Category | Characteristics | Examples | Use With Caution |
      |----------|-----------------|----------|------------------|
      | **Script** | Connected or flowing, mimics handwriting | Brush Script, Snell Roundhand | Headlines only, never body text |
      | **Display** | Designed for large sizes, decorative | Impact, Playfair Display | Headlines only, loses detail at small sizes |
      | **Monospace** | Equal-width characters | Courier, Fira Code, JetBrains Mono | Code, tabular data |
      
      ## Checking Family Completeness
      
      A complete type family for professional use should include:
      
      ### Essential
      - [ ] Regular (400 weight)
      - [ ] Bold (700 weight)
      - [ ] Regular Italic
      - [ ] Bold Italic
      
      ### Ideal
      - [ ] Light (300)
      - [ ] Medium (500)
      - [ ] Semibold (600)
      - [ ] All weights in italic
      - [ ] Small caps
      - [ ] Multiple figure styles (see below)
      
      ### Figure Styles
      
      | Style | Description | Use Case |
      |-------|-------------|----------|
      | **Lining figures** | 1234567890 - Uniform height, align with capitals | Headlines, tables, all-caps text |
      | **Oldstyle figures** | 1234567890 - Varying heights, blend with lowercase | Body text, running prose |
      | **Tabular figures** | Equal-width digits | Tables, spreadsheets, aligned numbers |
      | **Proportional figures** | Variable-width digits | Running text, when tabular not needed |
      
      Good web fonts offer figure variants via OpenType features:
      
      ```css
      /* Oldstyle figures */
      .prose { font-feature-settings: "onum" 1; }
      
      /* Tabular lining figures */
      .table { font-feature-settings: "lnum" 1, "tnum" 1; }
      ```
      
      ## Quick Recognition Guide
      
      When evaluating an unfamiliar typeface, check these distinguishing characters:
      
      | Character | What to Look For |
      |-----------|------------------|
      | **a** | One-story (ɑ) or two-story (a)? |
      | **g** | One-story or two-story (with ear/link)? |
      | **R** | Leg straight or curved? |
      | **Q** | Tail style |
      | **&** | Often distinctive |
      | **@** | Unique treatment reveals personality |
      | **Il1** | How distinct are these? (critical for legibility) |
      | **O0** | How distinct are these? |
      
      ## Terminology for Communication
      
      When discussing typefaces with others:
      
      **Instead of:** "The text looks weird"
      **Say:** "The x-height feels small for this size" or "The letter spacing is too tight"
      
      **Instead of:** "I don't like this font"
      **Say:** "The stroke contrast is too high for body text" or "The apertures are too closed for screen readability"
      
      **Instead of:** "Make it look more modern"
      **Say:** "Try a geometric sans" or "Consider lower stroke contrast"
      
      Using precise terminology helps teams make better decisions and keeps feedback actionable.
      
  • SKILL.md 17.7 KB
    ---
    name: web-typography
    description: 'Select, pair, and implement typefaces for web projects. Use when the user mentions "font pairing", "which typeface", "line height", "responsive typography", "web font loading", "type hierarchy", "variable fonts", "FOUT/FOIT", "typographic scale", or "the text is hard to read". Also trigger when choosing between system fonts and web fonts, optimizing font-loading performance, or designing readable long-form content. Covers readability evaluation, CSS implementation, and performance optimization. For overall UI design systems, see refactoring-ui. For dramatic typographic experiences, see top-design.'
    license: MIT
    metadata:
      author: wondelai
      version: "1.5.0"
    ---
    
    # Web Typography
    
    A practical guide to choosing, pairing, and implementing typefaces for the web. The best typography is invisible — it immerses readers in content rather than calling attention to itself.
    
    ## Core Principle
    
    **Typography is the voice of your content.** The typeface you choose sets tone before a single word is read — a legal site shouldn't feel playful; a children's app shouldn't feel corporate. Follow the "clear goblet" principle: typography should be like a crystal-clear wine glass, keeping focus on the wine (content), not the glass (type).
    
    ## Scoring
    
    **Goal: 10/10.** Score = number of the 10 Quick Diagnostic rows the implementation satisfies. Bands: **9-10** = body 16px+, measure under 75ch, line-height 1.4+, clear level contrast, font payload under 200KB, fallbacks set, survives 200% zoom; **5-6** = readable but missing measure control, fallbacks, or zoom resilience; **<=3** = sub-16px body, no measure cap, FOIT, or unreadable hierarchy. Always state the current score and the specific diagnostic rows failing.
    
    ## Two Contexts for Type
    
    All typography falls into two categories:
    
    | Context | Purpose | Priorities |
    |---------|---------|------------|
    | **Type for a moment** | Headlines, buttons, navigation, logos | Personality, impact, distinctiveness |
    | **Type to live with** | Body text, articles, documentation | Readability, comfort, endurance |
    
    **Workhorse typefaces** excel at "type to live with" — versatile across sizes, weights, and contexts without drawing attention. Examples: Georgia, Source Sans, Freight Text, FF Meta.
    
    ## Typography Framework
    
    ### 1. How We Read
    
    **Core concept:** Understanding reading mechanics is the foundation for every typography decision. Eyes don't scan smoothly — they jump in bursts.
    
    **Why it works:** Fighting these mechanics creates friction that drives readers away; aligning with them lets readers absorb content faster with less fatigue.
    
    **Key insights:**
    - **Saccades** — eyes jump in 7-9 character bursts; line length and letter spacing directly affect saccade efficiency
    - **Fixations** — eyes pause briefly to absorb content; dense or poorly spaced text slows reading
    - **Word shapes (bouma)** — experienced readers recognize word silhouettes, not individual letters
    - **Legibility vs. readability** — legibility is whether characters can be distinguished (a typeface concern); readability is whether text can be comfortably read for extended periods (a typography concern: size, spacing, line length). A legible typeface can still be set unreadably
    
    **Product applications:**
    
    | Context | Application | Example |
    |---------|------------|---------|
    | Long-form content | Optimize for sustained comfort | 16-18px body, 1.5-1.7 line height, 45-75 char lines |
    | Dashboard UI | Optimize for rapid scanning | Distinct weight hierarchy, whitespace between data groups |
    | Mobile reading | Account for distance and lighting | Larger body (17-18px), higher contrast |
    
    **Copy patterns:**
    ```css
    .prose {
      font-size: 1.125rem;     /* 18px */
      line-height: 1.6;
      max-width: 65ch;          /* ~45-75 characters */
    }
    ```
    
    See: [references/typeface-anatomy.md](references/typeface-anatomy.md) when you need to name letterform parts (x-height, counter, aperture) or place a face in a classification system to justify a choice.
    
    ### 2. Evaluating Typefaces
    
    **Core concept:** A typeface must pass technical, structural, and practical quality checks before it earns a place in a project. Beautiful specimens fail on screen.
    
    **Why it works:** Screen rendering, variable bandwidth, and diverse devices impose constraints print never faced. Rigorous evaluation prevents costly mid-project typeface swaps.
    
    **Key insights:**
    - **Technical quality** — consistent stroke weights, even visual color across text blocks, good kerning pairs (AV, To, Ty), complete character set, multiple weights (minimum: regular, bold, italic)
    - **Structural assessment** — generous x-height (better screen readability), open counters and apertures (a, e, c), distinct letterforms (Il1, O0, rn vs. m)
    - **Practical needs** — test at actual use sizes on target screens, check file size, verify the license
    - **Real content testing** — Lorem ipsum hides problems with character frequency, word length, and paragraph rhythm
    
    **Product applications:**
    
    | Context | Application | Example |
    |---------|------------|---------|
    | Body text selection | Prioritize x-height, open counters, even color | Source Serif Pro over Didot for long reads |
    | UI/System text | Prioritize small-size legibility and weight range | Inter or SF Pro for interface elements |
    | Multilingual product | Verify glyph coverage for target languages | Noto Sans for broad Unicode support |
    
    **Copy patterns:**
    ```css
    /* Stress-test at every actual use size */
    body { font-size: 16px; }
    .caption { font-size: 0.75rem; }
    h1 { font-size: 3rem; }
    ```
    
    **Ethical boundary:** Always verify the web license before shipping a font — desktop/print licenses rarely cover web embedding, and unlicensed use creates real legal liability.
    
    See: [references/evaluating-typefaces.md](references/evaluating-typefaces.md) when vetting a candidate face — full quality checklist, red-flags table, and the structural criteria to inspect.
    
    ### 3. Choosing Typefaces
    
    **Core concept:** Start with purpose, not aesthetics. The content's tone, reading context, and duration should drive selection — not personal preference or trends.
    
    **Why it works:** Purpose-driven choices feel inevitable rather than arbitrary, and survive stakeholder review because they can be justified with reasoning rather than taste.
    
    **Key insights:**
    - **Define the job first** — body text, headlines, and UI elements may each need different faces
    - **Match tone to content** — a financial report needs a different voice than a bakery menu
    - **Check the family** — confirm needed weights, italics, and styles exist before committing
    - **Safe starting points** — body serif: Georgia, Source Serif Pro, Charter; body sans: system fonts, Source Sans Pro, Inter, IBM Plex Sans
    
    **Product applications:**
    
    | Context | Application | Example |
    |---------|------------|---------|
    | Content-heavy site | Workhorse serif or sans for sustained reading | Source Serif Pro or Charter for articles |
    | SaaS dashboard | Clean sans with strong tabular figures | Inter or IBM Plex Sans for data-rich UIs |
    | Accessibility-focused | Faces designed for maximum legibility | Atkinson Hyperlegible for vision-impaired users |
    
    **Copy patterns:**
    ```css
    /* Web font with system fallback stack */
    body {
      font-family: 'Source Sans Pro', -apple-system,
                   BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    }
    ```
    
    See: [references/evaluating-typefaces.md](references/evaluating-typefaces.md) when narrowing finalists or weighing free vs. paid faces — the side-by-side comparison method and quality-option shortlists.
    
    ### 4. Pairing Typefaces
    
    **Core concept:** Successful pairings create clear contrast — faces should be obviously different, not confusingly similar. One to two typefaces maximum.
    
    **Why it works:** Clear structural contrast (serif + sans, light + bold, humanist + geometric) gives each face a distinct role. Faces that are too similar create tension without purpose — readers sense something is "off" without knowing why.
    
    **Key insights:**
    - **Contrast types** — structure (serif + sans), weight (light + regular), era (humanist + geometric), width (condensed + normal)
    - **Same designer strategy** — faces by one designer often share harmonizing DNA (FF Meta + FF Meta Serif)
    - **Superfamilies** — families designed to work together eliminate guesswork (Roboto + Roboto Slab)
    - **Pairing failures** — two near-identical faces, both faces competing for attention, one face overwhelming the other
    
    **Product applications:**
    
    | Context | Application | Example |
    |---------|------------|---------|
    | Editorial site | Serif headlines + sans body | Playfair Display + Source Sans Pro |
    | Documentation | Monospace code + sans prose from one family | IBM Plex Mono + IBM Plex Sans |
    | Minimal brand | Single family with weight variation | Inter at varying weights and sizes |
    
    **Copy patterns:**
    ```css
    /* Classic serif + sans-serif pairing */
    h1, h2, h3 { font-family: 'Playfair Display', Georgia, serif; }
    body { font-family: 'Source Sans Pro', -apple-system, sans-serif; }
    ```
    
    See: [references/pairing-strategies.md](references/pairing-strategies.md) when picking a second face — proven combinations, the contrast-type table, and same-designer/superfamily shortcuts.
    
    ### 5. Typographic Measurements
    
    **Core concept:** Three measurements — font size, line length, and line height — form the foundation of comfortable reading. Getting these right matters more than typeface choice.
    
    **Why it works:** These measurements govern how the eye tracks across and down text: optimal line length matches the saccade pattern, adequate line height prevents the eye from jumping to the wrong line on the return sweep, and sufficient size makes letterforms recognizable on screen.
    
    **Key insights:**
    - **Body size** — 16px minimum; err larger (18px) for reading-heavy sites; mobile users hold phones farther than designers assume
    - **Line length (measure)** — 45-75 characters ideal, 66 optimal; enforce with `ch` units or `max-width`
    - **Line height** — 1.4-1.8 for body; longer lines need more; headlines need tighter (1.1-1.25)
    - **Heading scale** — consistent ratio (1.2-1.5) between levels creates hierarchy without extremes
    
    **Product applications:**
    
    | Context | Application | Example |
    |---------|------------|---------|
    | Blog / article | 65ch max-width, 1.6 line height | `.prose { max-width: 65ch; line-height: 1.6; }` |
    | Dashboard | Tighter line height for dense data | `line-height: 1.3;` for table cells and labels |
    | Landing page | Generous sizing for scanability | `font-size: 1.25rem; line-height: 1.7;` |
    
    **Copy patterns:**
    ```css
    .prose {
      font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
      line-height: 1.6;
      max-width: 65ch;
    }
    /* Line height by context */
    h1, h2 { line-height: 1.1; }      /* headlines: 1.1-1.25 */
    .ui-text { line-height: 1.35; }   /* UI: 1.3-1.4 */
    .body-text { line-height: 1.6; }  /* body: 1.5-1.7 */
    ```
    
    See: [references/responsive-typography.md](references/responsive-typography.md) when writing the `clamp()` formulas — how to derive min/preferred/max and viewport-based measurement strategies.
    
    ### 6. Building Type Hierarchies
    
    **Core concept:** Hierarchy tells readers what matters most. Create distinction through controlled variation in size, weight, and color — but don't pull all three levers at once.
    
    **Why it works:** Deliberate, consistent differences between levels let readers grasp page structure at a glance; without hierarchy everything competes and nothing wins.
    
    **Key insights:**
    - **Three levers** — size, weight, color; vary one or two between adjacent levels, never all three
    - **The squint test** — squinting at a page should still reveal the hierarchy
    - **Consistent scale** — a modular ratio (1.2-1.5) between heading levels creates rhythm; arbitrary sizes create noise
    - **Don't skip levels** — jumping H1 to H3 breaks the reader's mental model
    
    **Product applications:**
    
    | Context | Application | Example |
    |---------|------------|---------|
    | Content page | Size + weight across 4-5 levels | H1 2.5rem/700, H2 1.75rem/600, Body 1rem/400 |
    | Dashboard | Weight + color for data vs. labels | Bold #111 values, regular #666 labels |
    | Form UI | Subtle weight shift for labels | Label: 600 weight, input: 400 weight |
    
    **Copy patterns:**
    ```css
    h1 { font-size: clamp(2rem, 1.5rem + 2vw, 3rem); font-weight: 700; color: #111; }
    h2 { font-size: clamp(1.5rem, 1.25rem + 1vw, 2rem); font-weight: 600; color: #111; }
    body { font-size: 1rem; font-weight: 400; color: #333; }
    .secondary { font-size: 0.875rem; color: #666; }
    /* Headings: more space above than below */
    h1, h2, h3 { margin: 1.5em 0 0.5em; line-height: 1.2; }
    ```
    
    **Ethical boundary:** Don't bury fees, disclaimers, or opt-outs in small or low-contrast type to demote what users need to see — hierarchy that hides material information weaponizes typography against the reader.
    
    See: [references/css-implementation.md](references/css-implementation.md) when implementing the CSS — full hierarchy patterns, `@font-face` loading, `font-variation-settings` axes, and subsetting with pyftsubset.
    
    ### 7. Responsive Typography and Web Font Performance
    
    **Core concept:** Type must adapt to screens, and web fonts must load efficiently. Fluid typography with `clamp()` eliminates breakpoint jumps; strategic font loading prevents layout shift and slow renders.
    
    **Why it works:** A fixed font size cannot serve both a 320px phone and a 1440px desktop. Web fonts are render-blocking by default — unoptimized loading causes Flash of Invisible Text (FOIT) or Flash of Unstyled Text (FOUT).
    
    **Key insights:**
    - **Fluid typography** — `clamp(min, preferred, max)` scales smoothly between viewports, no media queries needed for type
    - **Breakpoint adjustments** — mobile needs slightly larger body (17-18px) and a tighter heading scale; desktop can push display sizes while keeping line-length limits
    - **Loading strategy** — `font-display: swap` shows fallback text immediately; preload critical fonts; subset to needed characters
    - **Performance budget** — under 200KB total font payload; prefer WOFF2; a variable font can replace 4-6 static weight files
    
    **Product applications:**
    
    | Context | Application | Example |
    |---------|------------|---------|
    | Content site | Fluid sizes with clamp() | `font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem)` |
    | E-commerce | Preload hero font, lazy-load secondary weights | `<link rel="preload" href="font.woff2" as="font">` |
    | Global product | Subset per language to cut payload | Latin subset for English, CJK subset for Asian pages |
    
    **Copy patterns:**
    ```css
    h1 { font-size: clamp(2rem, 1.5rem + 2vw, 3.5rem); }
    
    @font-face {
      font-family: 'Custom Font';
      src: url('/fonts/custom.woff2') format('woff2');
      font-display: swap;
      unicode-range: U+0000-00FF; /* Latin subset */
    }
    /* In <head>: <link rel="preload" href="/fonts/custom.woff2" as="font" type="font/woff2" crossorigin> */
    ```
    
    **Ethical boundary:** Don't optimize users out — subsetting that drops characters non-English readers need, or removing italic/bold weights needed for emphasis, trades inclusivity for speed.
    
    ## Common Mistakes
    
    | Mistake | Why It Fails | Fix |
    |---------|-------------|-----|
    | Text feels cramped | Tight line height fatigues readers | Increase line-height to 1.6+; add paragraph spacing |
    | Lines too long | Beyond 75 chars the eye loses the return sweep | `max-width: 65ch` on text containers |
    | Headings look disconnected | Excess space above breaks association with content | Reduce space above heading; keep space below |
    | Text looks blurry | Font-smoothing or subpixel rendering issues | Check font-smoothing; try different weight; increase size |
    | Fonts loading slowly | Unoptimized files block rendering | Subset; `font-display: swap`; preload critical fonts |
    | Body text too small | Phones held farther than assumed; strains older eyes | Increase to 18px; test at real distance |
    | Hierarchy is unclear | Insufficient contrast between levels | Increase size/weight differences |
    | Typefaces clash | Pairing without clear contrast creates tension | One family, or ensure structural contrast (serif + sans) |
    | Lorem ipsum testing | Dummy text hides rhythm and frequency problems | Test with real, representative content |
    
    ## Quick Diagnostic
    
    | Question | If No | Action |
    |----------|-------|--------|
    | Is body text 16px or larger? | Too small for comfortable reading | At least 16px; prefer 18px for reading-heavy pages |
    | Is line length under 75 characters? | Eye loses position on return sweep | `max-width: 65ch` on prose containers |
    | Is line height 1.4+ for body? | Lines feel cramped, reading slows | Increase to 1.5-1.7 |
    | Is there clear contrast between type levels? | Hierarchy invisible, scanning fails | Increase size or weight differences |
    | Tested at actual sizes on real screens? | Rendering surprises in production | Test every use size on target devices |
    | Is total font payload under 200KB? | Slow loading hurts UX and SEO | Subset, WOFF2, consider variable fonts |
    | Are fallback fonts specified? | FOIT leaves blank text | System fallbacks in every font-family |
    | Does the page work at 200% zoom? | Accessibility failure for low vision | Fix overflow and truncation at 200% |
    | Are headings free of orphaned words? | Trailing words look unfinished | `text-wrap: balance` or manual breaks |
    | Are links visually distinct? | Users can't find interactive elements | Color and/or underline distinction |
    
    ## Further Reading
    
    - [*"On Web Typography"*](https://www.amazon.com/Web-Typography-Jason-Santa-Maria/dp/1937557065?tag=wondelai00-20) by Jason Santa Maria (A Book Apart, 2014)
    
    ## About the Author
    
    **Jason Santa Maria** is a graphic designer and educator who served as Creative Director at Typekit (now Adobe Fonts) and co-founded A Book Apart. He teaches at the School of Visual Arts in New York, and *On Web Typography* distills his bridge between traditional typographic craft and the realities of designing for screens.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related