Text and font styling

Font stacks, size, weight, line height, spacing and alignment for text that is comfortable to read.

  • Beginner
  • 7 min read
  • Updated 17 Oct 2026

What you will learn

  • Write font stacks with fallbacks
  • Set a readable type scale
  • Control line height, spacing and alignment
  • Style links and decorations clearly

Most of the web is text. A few typography properties, set well once on body and the headings, make every page easier to read. This lesson covers those properties and sensible values for each.

font-family and font stacks

font-family takes a comma-separated list of fonts. The browser uses the first one that is available:

CSS
body {
    font-family: "Source Sans 3", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

This list is called a font stack. It always ends with a generic family, which the browser maps to a font that definitely exists:

Generic familyLooks like
serifFonts with small strokes at the ends, such as Georgia
sans-serifClean fonts without them, such as Arial
monospaceEvery character the same width, for code
system-uiThe operating system's interface font
cursive, fantasyRarely useful

Quote font names that contain spaces. Never quote the generic families: "sans-serif" in quotes means a font literally called "sans-serif", which does not exist.

The system font stack

Using the operating system's own font is fast (nothing to download) and looks native on every device:

CSS
body {
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

code,
pre {
    font-family: ui-monospace, "Cascadia Code", Menlo, Consolas, monospace;
}

Loading your own fonts with @font-face comes in the web fonts lesson.

font-size and a type scale

Set body text in rem so it respects the user's settings, then size headings relative to it:

CSS
body {
    font-size: 1rem;
}

h1 { font-size: 2.5rem; }
h2 { font-size: 2rem; }
h3 { font-size: 1.5rem; }
h4 { font-size: 1.25rem; }

small,
.text-small {
    font-size: 0.875rem;
}

A type scale is a consistent set of sizes like this, often generated by multiplying by a ratio such as 1.25. Using a fixed set, rather than a different size for every element, makes a design look deliberate.

Body text at the browser default of 16px (1rem) is a sensible minimum for most sites. Going smaller for main content makes reading harder for many people. Making sizes grow smoothly with the screen is covered in the Responsive Web Design course.

font-weight

CSS
h1, h2, h3 {
    font-weight: 700;
}

.lead {
    font-weight: 300;
}

Weights run from 100 (thin) to 900 (black). 400 is normal and 700 is bold; the keywords normal and bold mean the same. A font only shows the weights it actually has. If you ask for 300 and the font has no light version, the browser picks the closest available weight.

line-height

line-height sets the height of each line, which controls the space between lines of text. It has more effect on readability than any other property.

CSS
body {
    line-height: 1.5;
}

h1, h2, h3 {
    line-height: 1.2;
}

Always use a unitless number. Around 1.5 suits body text; large headings look better tighter, around 1.1 to 1.3, because the gap grows with the font size.

Letter and word spacing

CSS
.eyebrow {
    font-size: 0.875rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

letter-spacing adds space between characters. Use em so it scales with the text. Uppercase text and small labels often benefit from a little extra; body text rarely needs any.

text-transform: uppercase changes only the appearance. Write the text in normal case in your HTML. Some screen readers spell out text typed in capitals letter by letter, and copied text keeps its original case.

Text alignment

CSS
.hero {
    text-align: center;
}

.price {
    text-align: end;    /* right in left-to-right languages */
}

Values include start, end, left, right, center and justify. Prefer start and end, which flip automatically for right-to-left languages.

Keep long paragraphs left-aligned (start-aligned). Centred text is fine for a short heading or two lines, but ragged left edges make longer text tiring to read. justify can create uneven gaps between words, especially in narrow columns.

Line length

Comfortable lines usually hold somewhere between 45 and 75 characters. Cap the width of text containers with ch:

CSS
.prose {
    max-width: 65ch;
}

Balanced headings

text-wrap: balance asks the browser to spread a heading's words evenly across its lines, so you do not get one lonely word on the last line:

CSS
h1, h2, h3 {
    text-wrap: balance;
}

p {
    text-wrap: pretty;
}

text-wrap: pretty makes smarter line breaks in paragraphs, such as avoiding a single short word on the last line. Both are progressive enhancements: browsers that do not support them simply wrap normally. Check their Baseline status on web.dev.

CSS
a {
    color: #0b5394;
    text-decoration-thickness: 0.08em;
    text-underline-offset: 0.15em;
}

a:hover {
    text-decoration-thickness: 0.15em;
}

text-decoration controls underlines. Rather than removing them, modern properties let you make them look good: text-decoration-thickness, text-underline-offset and text-decoration-color. Keep links in body text underlined so they do not rely on colour alone. You will style hover and focus states properly in the pseudo-classes lesson.

Other useful properties

CSS
.label {
    font-style: italic;
    font-variant-numeric: tabular-nums;  /* digits line up in columns */
}

.long-url {
    overflow-wrap: anywhere;             /* break long words instead of overflowing */
}

.title {
    font: 700 2rem/1.2 Georgia, serif;   /* shorthand: weight size/line-height family */
}

The font shorthand resets every font property it does not mention, so use it deliberately, typically only on body.

Putting it together

CSS
body {
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    font-size: 1rem;
    line-height: 1.6;
    color: #1f2933;
}

h1, h2, h3 {
    font-family: Georgia, "Times New Roman", serif;
    line-height: 1.2;
    font-weight: 700;
    text-wrap: balance;
}

h1 { font-size: 2.5rem; }
h2 { font-size: 1.75rem; }

.prose {
    max-width: 65ch;
}

a {
    color: #0b5394;
    text-underline-offset: 0.15em;
}

Checking fonts in DevTools

Select an element and open the Computed tab. At the bottom, Chrome lists Rendered Fonts: the font that was actually used. If it shows a fallback instead of the font you asked for, the font is not installed, not loaded, or misspelt in your stack.

Summary

  • Write font stacks that end with a generic family, and quote names with spaces.
  • Size text in rem with a consistent type scale; keep body text at a readable size.
  • Use unitless line-height, around 1.5 for body text and tighter for headings.
  • Keep lines around 45 to 75 characters with max-width in ch.
  • Prefer start alignment for paragraphs, keep links underlined, and write capitals in CSS, not HTML.