← Back to CSS3 Mastery
Intermediate14 min read

Typography & Fonts

Master web typography — font loading strategies, fluid type scales, readable line lengths, and pairing techniques for professional interfaces.

Font Loading with @font-face

The @font-face rule loads custom fonts. Specify font-family, src URLs with format hints, font-weight, and font-style. Use woff2 as the primary format — it offers the best compression and is supported by all modern browsers.

Always provide a fallback stack. List similar system fonts after your custom font so text remains readable during loading and if the font fails.

  • font-display: swap shows fallback text immediately, then swaps
  • Variable fonts pack all weights in one file — fewer HTTP requests
  • Subset fonts to include only needed characters for smaller files
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

body {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
}

Type Scale and Hierarchy

A type scale defines consistent size relationships between heading levels and body text. Modular scales (1.250 major third, 1.333 perfect fourth) produce harmonious proportions.

Define your scale as CSS variables and use them everywhere. This ensures that changing the base size ripples through the entire hierarchy consistently.

:root {
  --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: 1.875rem;
  --text-4xl: 2.25rem;
}

Readability Fundamentals

Body text should be 16px minimum (1rem). Line height of 1.5–1.7 for body copy improves readability. Line length should stay between 45 and 75 characters — use max-width: 65ch on text containers.

Letter-spacing (tracking) affects readability at different sizes. Headlines benefit from slightly tight tracking (negative letter-spacing), while small caps and uppercase labels need wider tracking.

  • Use ch units for max-width — 1ch equals the width of the "0" character
  • Increase line-height for wider line lengths
  • Avoid pure black (#000) on white — use dark gray for reduced eye strain
.prose {
  font-size: 1rem;
  line-height: 1.7;
  max-width: 65ch;
  color: var(--color-text);
}

.prose h2 {
  font-size: var(--text-2xl);
  line-height: 1.3;
  letter-spacing: -0.02em;
  margin-top: 2em;
}

Fluid Typography

Fluid typography scales smoothly between viewport sizes using clamp(). Define minimum size, preferred size (often viewport-relative), and maximum size. This eliminates jarring size jumps at breakpoints.

Apply fluid scaling to headings and display text. Body text can remain fixed at 1rem since readability does not improve with larger viewports.

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

.lead {
  font-size: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
  line-height: 1.6;
}

Font Feature Settings

OpenType features enhance typography. Font-variant-numeric: tabular-nums aligns numbers in tables. Font-feature-settings: "liga" 1 enables ligatures. Text-rendering: optimizeLegibility improves kerning on headings.

Use font-weight with variable fonts for precise weight control. Weight 450 or 550 can look better than standard 400/700 on certain typefaces.

.data-table td {
  font-variant-numeric: tabular-nums;
}

.headline {
  font-weight: 650;
  text-rendering: optimizeLegibility;
}

Get In Touch


Ready to discuss your next project? Drop me a message.