Typography and color

Why:Most of a page is text, and the typeface, size, line height and color decide whether anyone reads it. Afterwards you’ll be able to choose a typeface and a line length, write colors in modern formats and check contrast against WCAG.

30 minutes

Read by speech synthesis (Qwen3-TTS); the voice is not a person’s.

Typography is the set of rules that make text easy to read: typeface, size, line height and line length. Colors are checked by WCAG contrast.

Text is the interface

Most of any site is text, and how it is set decides whether people read to the end. Typography isn’t about beauty at all: it is the rules by which text stops getting in the way of reading. A few words we’ll use:

  • typeface: a family of letterforms such as Georgia; a font is one particular style of it (bold, italic);
  • size: how big the letters are;
  • leading, or line height: the distance between lines (line-height in CSS);
  • measure: the length of a line, in characters;
  • serifs: the small “feet” on the letters of some typefaces; typefaces without them are called sans serif.

Size, line height and measure

Three numbers that make text readable:

  • A body text size of 16 pixels or more (1rem and up). Any less and the reader will zoom in with their fingers on a phone. Many people choose 1.125rem (18px).
  • A line height of 1.4 to 1.7 times the size of the letters, set as a number with no unit: line-height: 1.6. Then it grows with the text. Headings get less, about 1.2: short lines don’t need as much air.
  • A line length of 45 to 75 characters. Robert Bringhurst, in The Elements of Typographic Style, calls 66 ideal. A line that is too long loses the reader on the way back, and one that is too short chops up the sentence. In CSS that is max-width: 65ch (the ch unit is the width of a zero in the current font, which is roughly one character).

Turn the sliders on the diagram. It is your own text.

Size, line height and line length

For fifteen years I have measured land and explained to courts where a boundary really runs. A surveyor first and a lawyer second, I see a dispute both in coordinates and in law. A good line reads without effort: the eye never loses the start of the next one.

A line of 65 characters: comfortable, between 45 and 80 characters. Line height: good, roughly 1.4 to 1.7.

Contrast of text and background

This is how ordinary text looks in this pair of colors, and below it large text.

Large text

Contrast: 7.61 to 1. Normal text: AA passes, AAA passes. Large text (from 24px, or from 19px bold): AA passes, AAA passes.

Check yourself: why is line height set as a number with no unit?

A number with no unit is multiplied by the element’s font size, so the line height grows and shrinks with the text. A value in pixels would stay the same.

Typefaces

A typeface is set with a list: font-family: Georgia, "Times New Roman", serif;. The browser takes the first one the reader has, and if they have none of them, it turns to the last item, a generic family (serif, sans-serif, monospace or system-ui, the system’s own typeface). That last one is always needed: without it, the text could be left with no typeface at all.

In the 1990s every computer had the same few fonts (Arial, Times, Courier), authors used only those, and so they were called “web safe”. Georgia and Verdana were designed by Matthew Carter specially for the screen and released in 1996, and for ten years they were the favorites of the web.

Today you can add any typeface with @font-face:

@font-face {
  font-family: "Riverbend Serif";
  src: url("riverbend-serif.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

What matters here:

  • the characters you need: the typeface must have every character your text uses, accented letters (é, ü), curly quotes, the € sign. Without them a fallback typeface fills the gaps, and the text turns patchy. Check the character set before you choose. A site in another script needs a typeface that has that script;
  • woff2: a compressed format that all modern browsers understand;
  • font-display: swap: until the file has loaded, the fallback typeface is shown, and then it is replaced. Without it the text is invisible until the font arrives (remember the blank screen from the first part);
  • unicode-range lets you load only the characters you need, for example a Latin subset. Another script needs a subset of its own;
  • your own files, not someone else’s server: a typeface linked from the Google Fonts servers makes every visitor’s browser contact a third party, and that sends the visitor’s IP address to it. This costs speed, and it is also a data protection matter, because an IP address can be personal data under the GDPR and the UK GDPR. In January 2022 the Regional Court of Munich ordered the owner of a website to pay a visitor €100 in damages for exactly this, and to stop doing it without consent (case 3 O 17493/20). One German judgment isn’t a rule for everyone, but a file kept next to your site removes the question, and it loads faster and doesn’t depend on anyone else. This is general information, not legal advice: for a real site, ask a lawyer or your data protection authority (in the UK, the ICO). Part 15 returns to the subject.

Our preview has no network, so the typefaces in the exercise are the system’s own. That is no loss: a good system set (Georgia, system-ui) looks excellent and weighs not a byte.

Check yourself: why end font-family with a generic family such as serif?

So the text always has a typeface: if none of the listed ones is there, the browser takes any typeface of the right kind.

Color

A color in CSS can be written in several ways, and all of them mean the same thing:

  • #1d5c63: hex, the hexadecimal notation and the most common;
  • rgb(29 92 99): the amounts of red, green and blue;
  • hsl(186 55% 25%): the hue (an angle on the color wheel), the saturation and the lightness. Handier for choosing: to get a darker shade, change the third number;
  • oklch(45% 0.07 200): a modern notation in which lightness is “honest”: the same lightness numbers look equally light. All modern browsers understand it, and it is good for palettes.

A palette doesn’t need many colors. Four roles are enough: text, background, surface (cards, header) and accent (button, link), plus neutrals. Three shades is good, five is a lot.

Contrast

Contrast is the ratio of the brightness of the text to the brightness of its background. It is measured by a number from 1 (identical) to 21 (black on white), and the WCAG standard asks for these at level AA:

  • 4.5 to 1 for ordinary text;
  • 3 to 1 for large text (from 24px, or from 18.66px bold) and for icons and the borders of fields;
  • level AAA is stricter: 7 to 1 and 4.5 to 1.

You can’t judge contrast by eye: the pair #767676 on white passes (4.54), and #777777 doesn’t (4.48), though you couldn’t tell them apart. So count. The commonest accessibility error on the web, according to the yearly WebAIM study, is light gray text on white. The calculator on the diagram above will help you choose a pair.

And one more thing: don’t carry meaning by color alone. Roughly one man in twelve sees red and green differently, so “required fields are marked in red” doesn’t work for him. Add an asterisk or a label.

Check yourself: what is the minimum contrast for ordinary text under WCAG AA?

4.5 to 1. For large text, 3 to 1 is enough.

Practice

This is your 2005 page from the last lesson, with two columns made with float. The text has to become readable: size, line height, measure and contrast. Choose the typeface to suit your project’s tone: serifs in the headings for a businesslike tone, a larger sans serif for a bold one. The main thing is that the contrast checks pass after your changes.

Write colors however you like: hex, rgb() or hsl(). If you want to try oklch(), the browser understands it too, but the exercise’s contrast check can read only the familiar notations, and an unusual format will make it report an unknown color.

What was wrong with 2005

Text was set small: Verdana at 10 to 11px was the norm, because screens were small and every pixel was guarded. Gray on gray looked refined. Headings and logos were often made as images to get a favorite typeface, and then neither a screen reader nor a search engine could read them, and zooming in meant a blurry picture. The contrast checks will remind you of all this.

Practice

Preparing your page…

Test

Question 1 of 6

What is a sensible minimum size for body text read on a screen?

One answer

Cards

These cards go into your review once you finish the lesson.

  • What are the numbers for readable text?

    Answer

    A size of 16px (1rem) or more, a line height of 1.4 to 1.7 with no unit, a line length of 45 to 75 characters (max-width: 65ch) and a contrast of at least 4.5 to 1.

  • How do you set a typeface?

    Answer

    With a list that has fallbacks: font-family: Georgia, serif. At the end comes a generic family (serif, sans-serif, system-ui), so the text is never left without a typeface.

  • How do you add a typeface of your own?

    Answer

    @font-face with a woff2 file and font-display: swap; the file must have the characters your text uses. Better to keep the font on your own site than to take it from someone else’s server.

  • What formats can a color be written in?

    Answer

    Hex (#1d5c63), rgb(29 92 99), hsl(186 55% 25%) and the modern oklch(45% 0.07 200). All of them work; hsl and oklch are handier for choosing shades.

  • How much contrast does WCAG AA need?

    Answer

    4.5 to 1 for ordinary text, and 3 to 1 for large text (from 24px, or from 18.66px bold) and for icons. The stricter level, AAA, needs 7 to 1 and 4.5 to 1.

Sources

Next

You now know: typography, web fonts, color formats, text contrast ratios.