Good typography is mostly invisible. Great typography makes content easier to read, creates hierarchy, and gives a design its personality. Here are 10 rules that improve every web project.
1. Limit yourself to two typefaces
Two fonts are almost always enough: one for headings, one for body. A third font can be introduced for accent or code, but more than three typefaces usually creates noise rather than richness. The discipline of two forces you to use weight, size, and colour for hierarchy instead.
2. Set line length between 60–80 characters
This is the sweet spot for reading comfort. Too narrow (under 45 characters) and the eye breaks the reading flow with too-frequent returns. Too wide (over 90 characters) and the eye gets lost tracking back to the next line. In CSS: max-width: 65ch on your body text container.
3. Use a modular type scale
Rather than choosing font sizes arbitrarily, use a scale based on a fixed ratio (e.g. 1.25 "Major Third" or 1.333 "Perfect Fourth"). Scales give visual rhythm to your headings and body text. Tools like typescale.com generate CSS for any scale.
4. Line height is not one-size-fits-all
Body text needs generous line height — around 1.5–1.7× the font size. Large headings (48px+) should be tighter — 1.0–1.2×. Applying the same line-height to both makes one or the other feel wrong.
5. Test at real sizes in real fonts
Mock-ups in Figma use system fonts by default. Always test with your actual chosen typeface before shipping. Small differences in x-height, letter spacing, and weight between fonts completely change how a design reads at body sizes. Use Typescope to preview your font choice with your actual copy before committing.
6. Colour contrast matters for legibility
WCAG AA requires a minimum contrast ratio of 4.5:1 for normal text and 3:1 for large text. Light grey text on a white background is a common failure. Use Typescope's Contrast Checker to verify your text/background combinations before you ship.
7. Embrace variable fonts
Variable fonts store a full range of weights (and sometimes width, slant, optical size) in a single file, dramatically reducing HTTP requests and file size. Fonts like Inter, Fraunces, Recursive, and Source Sans 3 are variable. Use them.
8. Don't use more than two different font sizes on a single card or component
Inside a card component, a name at 16px and a description at 14px is usually all you need. Adding a third size (say, a label at 11px) often creates visual noise without adding hierarchy value.
9. Optical alignment over mathematical alignment
Certain glyphs (round letters like O, pointed letters like A) appear smaller than flat-topped letters at the same mathematical size. Optically correct sizing means slightly oversizing round letterforms or adjusting letter-spacing to compensate. This is why well-designed type systems include optical size axes.
10. Use font loading strategies to prevent layout shift
Loading a custom web font without a fallback strategy causes a Flash of Invisible Text (FOIT) or Flash of Unstyled Text (FOUT), both of which damage Cumulative Layout Shift (CLS) scores. Use font-display: swap in your @font-face declarations, and choose a system fallback that is similar in x-height and width to your chosen font.