typography

CSS typography patterns for readable, beautiful text. Covers type scale, hierarchy, rhythm, font pairing, text-wrap, hanging punctuation, and OpenType features.

allowed_tools: Read, Write, Edit

$ インストール

git clone https://github.com/ProfPowell/project-template /tmp/project-template && cp -r /tmp/project-template/.claude/skills/typography ~/.claude/skills/project-template

// tip: Run this command in your terminal to install the skill


name: typography description: CSS typography patterns for readable, beautiful text. Covers type scale, hierarchy, rhythm, font pairing, text-wrap, hanging punctuation, and OpenType features. allowed-tools: Read, Write, Edit

Typography Skill

This skill covers CSS typography patterns for creating readable, aesthetically pleasing text. It addresses type scale, hierarchy, vertical rhythm, font pairing, and modern CSS text features.

Philosophy

Good typography:

  1. Establishes hierarchy - Readers scan before reading; size, weight, and spacing guide them
  2. Maintains rhythm - Consistent spacing creates visual harmony
  3. Optimizes readability - Line length, spacing, and contrast serve comprehension
  4. Respects the medium - Web typography adapts to screens and user preferences

Type Scale

A type scale provides consistent, harmonious font sizes based on a mathematical ratio.

Recommended Scale (Major Third - 1.25)

:root {
  /* Base size */
  --font-size-base: 1rem;      /* 16px */

  /* Scale down */
  --font-size-xs: 0.64rem;     /* 10.24px - fine print */
  --font-size-sm: 0.8rem;      /* 12.8px - captions, labels */

  /* Scale up */
  --font-size-md: 1rem;        /* 16px - body text */
  --font-size-lg: 1.25rem;     /* 20px - lead text, h4 */
  --font-size-xl: 1.563rem;    /* 25px - h3 */
  --font-size-2xl: 1.953rem;   /* 31.25px - h2 */
  --font-size-3xl: 2.441rem;   /* 39px - h1 */
  --font-size-4xl: 3.052rem;   /* 48.8px - display */
}

Common Scale Ratios

RatioNameMultiplierBest For
1.125Major SecondSubtleDense UIs, small screens
1.200Minor ThirdModerateGeneral purpose
1.250Major ThirdBalancedContent sites, blogs
1.333Perfect FourthPronouncedMarketing, editorial
1.414Augmented FourthBoldHero sections
1.618Golden RatioDramaticArtistic, display

Fluid Type Scale

Scale font sizes between breakpoints using clamp():

:root {
  /* Fluid scale: min, preferred, max */
  --font-size-base: clamp(1rem, 0.875rem + 0.5vw, 1.125rem);
  --font-size-lg: clamp(1.25rem, 1rem + 1vw, 1.5rem);
  --font-size-xl: clamp(1.5rem, 1.25rem + 1.5vw, 2rem);
  --font-size-2xl: clamp(1.875rem, 1.5rem + 2vw, 2.5rem);
  --font-size-3xl: clamp(2.25rem, 1.75rem + 2.5vw, 3.5rem);
}

Container-Responsive Typography

For components, use container query units:

product-card {
  container-type: inline-size;
}

product-card h3 {
  font-size: clamp(1rem, 0.875rem + 2cqi, 1.5rem);
}

Type Hierarchy

Hierarchy guides readers through content using size, weight, spacing, and color.

Heading Styles

/* Headings reset and base */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-tight);
  text-wrap: balance;  /* Balanced line lengths */
}

h1 {
  font-size: var(--font-size-3xl);
  letter-spacing: -0.02em;  /* Tighten large text */
  margin-block: 0 var(--spacing-lg);
}

h2 {
  font-size: var(--font-size-2xl);
  letter-spacing: -0.01em;
  margin-block: var(--spacing-2xl) var(--spacing-md);
}

h3 {
  font-size: var(--font-size-xl);
  margin-block: var(--spacing-xl) var(--spacing-sm);
}

h4 {
  font-size: var(--font-size-lg);
  margin-block: var(--spacing-lg) var(--spacing-sm);
}

h5, h6 {
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.05em;  /* Loosen small caps */
  margin-block: var(--spacing-md) var(--spacing-xs);
}

Body Text Styles

/* Prose container for article content */
article, .prose {
  font-size: var(--font-size-md);
  line-height: var(--line-height-relaxed);
  text-wrap: pretty;  /* Improved line breaking */

  & p {
    margin-block: 0 var(--spacing-md);
    max-inline-size: 65ch;  /* Optimal line length */
  }

  & p:last-child {
    margin-block-end: 0;
  }
}

/* Lead paragraph */
.lead, article > p:first-of-type {
  font-size: var(--font-size-lg);
  line-height: var(--line-height-normal);
  color: var(--text-muted);
}

Supporting Text Styles

/* Captions, labels, fine print */
small, .caption, figcaption {
  font-size: var(--font-size-sm);
  color: var(--text-muted);
}

/* Emphasized text */
strong, b {
  font-weight: var(--font-weight-semibold);
}

/* Code inline */
code {
  font-family: var(--font-mono);
  font-size: 0.875em;  /* Relative to parent */
  background: var(--surface-elevated);
  padding-inline: 0.25em;
  border-radius: var(--radius-sm);
}

Vertical Rhythm

Vertical rhythm creates consistent spacing based on line height, creating visual harmony.

Establishing a Baseline

:root {
  --baseline: 1.5rem;  /* Based on body line-height */

  /* Spacing as multiples of baseline */
  --spacing-xs: calc(var(--baseline) * 0.25);   /* 6px */
  --spacing-sm: calc(var(--baseline) * 0.5);    /* 12px */
  --spacing-md: var(--baseline);                 /* 24px */
  --spacing-lg: calc(var(--baseline) * 1.5);    /* 36px */
  --spacing-xl: calc(var(--baseline) * 2);      /* 48px */
  --spacing-2xl: calc(var(--baseline) * 3);     /* 72px */
}

Line Height Guidelines

Content TypeLine HeightToken
Headings1.1 - 1.3--line-height-tight
Body text1.5 - 1.6--line-height-normal
Long-form prose1.6 - 1.8--line-height-relaxed
UI labels1.2 - 1.4--line-height-tight
:root {
  --line-height-tight: 1.25;
  --line-height-normal: 1.5;
  --line-height-relaxed: 1.75;
}

Rhythm-Aligned Spacing with round()

Ensure spacing aligns to the typographic grid:

.card {
  /* Round gap to quarter-line increments */
  --gap: round(up, 2cqi, calc(var(--baseline) * 0.25));
  gap: var(--gap);
}

Font Pairing

Effective font pairing creates contrast while maintaining harmony.

Pairing Strategies

StrategyExampleUse Case
ContrastSerif heading + Sans bodyEditorial, blogs
SuperfamilySame family, different weightsCorporate, minimal
ComplementarySimilar x-height, different styleProfessional, versatile

Safe System Font Stacks

:root {
  /* Sans-serif (headings and UI) */
  --font-sans: system-ui, -apple-system, BlinkMacSystemFont,
               "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* Serif (body text, editorial) */
  --font-serif: "Iowan Old Style", "Palatino Linotype",
                Palatino, Georgia, serif;

  /* Monospace (code) */
  --font-mono: ui-monospace, "Cascadia Code", "Source Code Pro",
               Menlo, Consolas, "DejaVu Sans Mono", monospace;
}

Popular Web Font Pairings

HeadingBodyMood
InterInterClean, neutral
Playfair DisplaySource Sans 3Elegant, editorial
MontserratOpen SansModern, friendly
OswaldLatoBold, contemporary
MerriweatherMerriweather SansReadable, professional
Space GroteskWork SansTechnical, geometric

Font Loading Pattern

<head>
  <!-- Preload critical fonts -->
  <link rel="preload" href="/fonts/heading.woff2"
        as="font" type="font/woff2" crossorigin="anonymous"/>

  <!-- Font-face with display swap -->
  <style>
    @font-face {
      font-family: "Heading";
      src: url("/fonts/heading.woff2") format("woff2");
      font-weight: 700;
      font-display: swap;
    }
  </style>
</head>

Text Layout Details

Modern CSS provides fine control over text wrapping and layout.

text-wrap Property

/* Balance: equal line lengths for headings */
h1, h2, h3, .headline {
  text-wrap: balance;
}

/* Pretty: improved line breaking for body text */
article, p, .prose {
  text-wrap: pretty;
}

/* Stable: prevent reflow in editable content */
textarea, [contenteditable] {
  text-wrap: stable;
}
ValueEffectUse For
balanceEqual-width linesHeadings, captions (≤6 lines)
prettyImproved rag, fewer orphansBody text, prose
stableNo reflow on editTextareas, contenteditable
nowrapNo wrappingLabels, buttons

Browser support: balance and pretty are widely supported. Safari's pretty implementation is most advanced.

Hanging Punctuation

Align text optically by letting punctuation hang outside the text box:

blockquote, .pullquote {
  hanging-punctuation: first last;
}

/* Opening quotes hang outside */
blockquote::before {
  content: open-quote;
}
ValueEffect
firstHang opening quote/punctuation
lastHang closing quote/punctuation
force-endHang periods/commas at line end
allow-endHang if it improves justification

Browser support: Safari only (as of 2025). Use as progressive enhancement.

Hyphenation

/* Enable hyphenation for narrow columns */
.narrow-column {
  hyphens: auto;
  hyphenate-limit-chars: 6 3 2;  /* word min, before break, after break */
  hyphenate-limit-lines: 2;      /* Max consecutive hyphenated lines */
}

/* Disable for headings */
h1, h2, h3 {
  hyphens: none;
}

Widows and Orphans

Control minimum lines at page/column breaks:

article {
  orphans: 3;  /* Min lines at bottom of page */
  widows: 3;   /* Min lines at top of page */
}

Note: These primarily affect print and multi-column layouts.


Optimal Line Length

The 45-75 Character Rule

/* Constrain prose to readable width */
article, .prose {
  max-inline-size: 65ch;  /* ~65 characters */
}

/* Wider for technical content */
.documentation {
  max-inline-size: 80ch;
}

/* Narrower for captions */
figcaption {
  max-inline-size: 45ch;
}

Line Length by Context

Content TypeOptimal WidthCSS
Body prose45-75chmax-inline-size: 65ch
HeadingsFull widthNo constraint
Captions35-50chmax-inline-size: 45ch
Code blocks80-120chmax-inline-size: 100ch

OpenType Features

Unlock advanced typographic features in professional fonts:

/* Enable common features */
body {
  font-feature-settings:
    "kern" 1,  /* Kerning */
    "liga" 1,  /* Standard ligatures */
    "calt" 1;  /* Contextual alternates */
}

/* Tabular figures for data */
.data-table td {
  font-variant-numeric: tabular-nums;
}

/* Old-style figures for prose */
article {
  font-variant-numeric: oldstyle-nums;
}

/* Small caps */
.section-label {
  font-variant-caps: small-caps;
  letter-spacing: 0.05em;
}

Common OpenType Features

FeatureCSSUse Case
Kerningfont-kerning: normalAlways enable
Ligaturesfont-variant-ligatures: common-ligaturesBody text
Tabular figuresfont-variant-numeric: tabular-numsTables, data
Oldstyle figuresfont-variant-numeric: oldstyle-numsProse
Small capsfont-variant-caps: small-capsLabels, acronyms
Fractionsfont-variant-numeric: diagonal-fractionsRecipes, specs

Variable Fonts

Variable fonts offer multiple weights/widths in a single file:

@font-face {
  font-family: "Inter";
  src: url("/fonts/Inter-Variable.woff2") format("woff2");
  font-weight: 100 900;  /* Range of weights */
  font-display: swap;
}

/* Use any weight in the range */
h1 { font-weight: 800; }
h2 { font-weight: 650; }
body { font-weight: 400; }
strong { font-weight: 600; }

Variable Font Axes

AxisPropertyValues
wghtfont-weight100-900
wdthfont-stretch50%-200%
slntfont-style-90 to 90
italfont-style0 or 1
opszfont-optical-sizingauto or size

Responsive Typography

Minimum Touch Targets

/* Ensure tappable text links */
nav a, button {
  min-block-size: 44px;
  padding-block: var(--spacing-sm);
}

Reduced Motion

@media (prefers-reduced-motion: reduce) {
  /* Disable text animations */
  * {
    transition-duration: 0.01ms !important;
  }
}

High Contrast Mode

@media (prefers-contrast: more) {
  body {
    /* Increase text contrast */
    --text: oklch(0% 0 0);
    --text-muted: oklch(25% 0 0);
  }
}

Dark Mode Typography

:root {
  color-scheme: light dark;

  /* Text colors adapt to theme */
  --text: light-dark(oklch(15% 0.01 260), oklch(95% 0.01 260));
  --text-muted: light-dark(oklch(40% 0.02 260), oklch(65% 0.02 260));
}

/* Reduce font weight in dark mode (appears bolder) */
@media (prefers-color-scheme: dark) {
  body {
    font-weight: 350;  /* Slightly lighter */
  }

  strong {
    font-weight: 550;
  }
}

Complete Typography Token System

@layer tokens {
  :root {
    /* ==================== FONTS ==================== */

    --font-sans: system-ui, -apple-system, BlinkMacSystemFont,
                 "Segoe UI", Roboto, sans-serif;
    --font-serif: "Iowan Old Style", Palatino, Georgia, serif;
    --font-mono: ui-monospace, "Cascadia Code", Menlo, monospace;

    --font-heading: var(--font-sans);
    --font-body: var(--font-sans);

    /* ==================== TYPE SCALE ==================== */

    --font-size-xs: 0.75rem;     /* 12px */
    --font-size-sm: 0.875rem;    /* 14px */
    --font-size-md: 1rem;        /* 16px */
    --font-size-lg: 1.125rem;    /* 18px */
    --font-size-xl: 1.25rem;     /* 20px */
    --font-size-2xl: 1.5rem;     /* 24px */
    --font-size-3xl: 1.875rem;   /* 30px */
    --font-size-4xl: 2.25rem;    /* 36px */
    --font-size-5xl: 3rem;       /* 48px */

    /* ==================== FONT WEIGHTS ==================== */

    --font-weight-light: 300;
    --font-weight-normal: 400;
    --font-weight-medium: 500;
    --font-weight-semibold: 600;
    --font-weight-bold: 700;

    /* ==================== LINE HEIGHTS ==================== */

    --line-height-none: 1;
    --line-height-tight: 1.25;
    --line-height-snug: 1.375;
    --line-height-normal: 1.5;
    --line-height-relaxed: 1.625;
    --line-height-loose: 2;

    /* ==================== LETTER SPACING ==================== */

    --letter-spacing-tighter: -0.05em;
    --letter-spacing-tight: -0.025em;
    --letter-spacing-normal: 0;
    --letter-spacing-wide: 0.025em;
    --letter-spacing-wider: 0.05em;
    --letter-spacing-widest: 0.1em;

    /* ==================== BASELINE GRID ==================== */

    --baseline: 1.5rem;
  }
}

Checklist

When implementing typography:

Scale & Hierarchy

  • Type scale uses consistent ratio (1.2-1.333)
  • Headings decrease in size logically (h1 > h2 > h3)
  • Body text is 16px minimum (1rem)
  • Line lengths constrained (max-inline-size: 65ch)

Rhythm & Spacing

  • Spacing derives from baseline grid
  • Line heights appropriate for content type
  • Margins create visual grouping (more space above headings)

Text Layout

  • text-wrap: balance on headings
  • text-wrap: pretty on body text
  • hanging-punctuation: first on blockquotes (progressive)
  • hyphens: auto only on narrow columns

Font Features

  • font-kerning: normal enabled
  • Tabular figures in data tables
  • font-display: swap for web fonts
  • Preload critical fonts

Accessibility

  • Minimum 44px touch targets for text links
  • Sufficient color contrast (WCAG AA)
  • Font size respects user preferences (use rem)
  • No text smaller than 12px

Related Skills

  • css-author - Design tokens, @layer organization
  • performance - Font loading, preload hints
  • accessibility-checker - Color contrast, text sizing
  • print-styles - Print typography adjustments
  • i18n - Multilingual typography considerations