Command Palette

Search for a command to run...

Hectal
PHASE 4Beginner ~26 min· topic 3 of 6

Topic 4.3

Size, Weight, Style and Line Height

In one line

font-size, font-weight, font-style and line-height set how big, how thick, how slanted and how spaced text is; a unitless line height and a line length of about 45–75 characters make text comfortable to read.

Think of it like this

Writing in a school notebook. The size of your letters, how hard you press (thin or thick strokes), whether you write slanted, and how far apart the ruled lines are all decide how easy your notes are to read. If the lines are too close, letters bump into each other; if the page is very wide, your eyes lose their place when they jump back to the next line.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

font-size
How big the letters are. The browser default is 16px.
font-weight
How thick the letters are, from thin (100) to black (900). 400 is normal, 700 is bold.
font-style
Whether text is upright (normal) or slanted (italic, oblique).
Italic
A slanted version of a font, drawn specially by the designer.
Synthesis
The browser faking bold or italic by thickening or slanting the normal letters when the real face is missing.
line-height
The height of each line of text, including the space between lines.
Unitless value
A plain number with no unit, like 1.5. For line-height it means "1.5 times my font size".
Shorthand
One property that sets several others at once, like font.
Measure
The length of a line of text, usually counted in characters.

Step by step

01Set a base size on the root

Leave the root at the user's default (100% = 16px unless they changed it) and size everything else in rem. Headings scale from that base.

style.csswhole filecss
html {
  font-size: 100%;
}
body {
  font-size: 1.125rem;  /* 18px with the default */
}
h1 {
  font-size: 2.25rem;   /* 36px */
}

02Choose weights and styles

Headings are bold by default in the browser's stylesheet (font-weight: bold). You can make them lighter or heavier. Use weights your font actually includes.

style.csswhole filecss
h1 {
  font-weight: 800;
}
.lead {
  font-weight: 300;
}
em, .note {
  font-style: italic;
}

03Give lines room with a unitless line height

Set line-height: 1.5 on body. Headings, with their bigger text, often look better tighter, around 1.1 to 1.25.

style.csswhole filecss
body {
  line-height: 1.5;
}
h1, h2 {
  line-height: 1.15;
}

04See why unitless matters

With 1.5em, the parent computes 1.5 × 16px = 24px and every child inherits 24px, even a 32px heading. With 1.5, each element inherits the number and computes its own: 24px for 16px text, 48px for 32px text.

See why unitless mattersdiagram
Rendering diagram…

05Limit the line length

Very long lines are tiring: your eye has trouble finding the start of the next line. Cap the text column's width in ch so it scales with the font.

style.csswhole filecss
article {
  max-width: 65ch;
  margin-inline: auto;  /* centre the column */
}

06Combine with the font shorthand (carefully)

The shorthand is compact, but it resets what you leave out. Write it first, then any longhand overrides after it.

style.csswhole filecss
body {
  font: 400 1.125rem/1.5 system-ui, sans-serif;
}
/* style, variant and stretch were reset to normal: fine here */

Try it yourself

  1. 1

    Predict the overlap

    In the first example, change .em { line-height: 1.5em; } to 150%. Predict the big child's line height before running. It is still 24px: a percentage is also computed once on the parent.

  2. 2

    Fix the shorthand

    In the second example, move line-height: 2; below the font line, or put it into the shorthand as font: 18px/2 Georgia, serif;. Predict the first console line. It becomes 36px (2 × 18px).

  3. 3

    Find a comfortable measure

    In the third example, try max-width: 40ch, then 90ch. Read a few lines of each. Most people find somewhere around 60–70 easiest.

Code & diagrams

The line-height inheritance trap New tab

Both parents compute 24px. Only the unitless one lets the big child compute its own line height.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

em parent: 24px | big child: 24px
unitless parent: 24px | big child: 48px
Shorthand resets and relative weights New tab

`font` came after `line-height` and silently set it back to `normal`. `bolder` steps up from the parent's weight: 400 → 700 → 900.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

.a line-height: normal
outer b: 700
inner b: 900
Readable measure New tab

`ch` is the width of the `0` character in the current font, so the limit grows and shrinks with the text size.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Line height in em on a container

Set body { font-size: 16px; line-height: 1.2em; } and give h1 a font-size of 3rem that wraps onto two lines.

terminal
$ the page shows
── what you'll see ──
The two lines of the heading overlap each other: 48px letters on 19.2px lines.

Break #2

Shorthand missing the family

Write font: bold 20px; on a heading.

terminal
$ DevTools → Styles
── what you'll see ──
font: bold 20px; (crossed out with a warning icon: Invalid property value)

Myth vs fact

Myth

font-weight: 900 always makes text heavier than 700.

Fact

Only if the font has a 900 face (or is variable). Otherwise the browser uses the closest available face, and 700 and 900 can look the same.

Myth

Use px for font sizes so the design stays exact.

Fact

Text sized in px (especially on the root) ignores the user's browser font-size setting, which people with low vision rely on. rem keeps the design proportional and respects that setting.

Myth

Line height adds space only below each line.

Fact

The extra space (line height minus the font's content height) is split in half: half above and half below the letters. That's why the first line of a paragraph has a little gap above it.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Line height is applied through line boxes: every inline box gets a height from its own line-height, and the line box must fit all of them. A small <sup> or a big inline icon can push one line taller than the others, which is why sup { line-height: 0; } appears in resets.

  • ▸

    The half-leading model splits the extra space above and below the glyphs, so text never sits flush with its container. The newer text-box: trim-both cap alphabetic (from text-box-trim / text-box-edge) trims that space so text aligns optically with icons and boxes; check support before relying on it.

  • ▸

    font-weight numbers 1–1000 and fractional values (like 550) are part of CSS Fonts Level 4; they only render differently with variable fonts. bolder/lighter use a mapping table: bolder of 100–349 → 400, 350–549 → 700, 550–899 → 900; lighter of 550–749 → 400, 750+ → 700, below 550 → 100.

  • ▸

    WCAG 1.4.12 (Text Spacing) requires that content still works when users force line height to 1.5 × the font size, paragraph spacing to 2 ×, letter spacing to 0.12 × and word spacing to 0.16 ×. Fixed heights on text boxes are the usual cause of clipped text in that test.

Remember this

  1. 1

    font-size sets the size of the letters. The browser default is 16px (the keyword medium). You can use px, rem (relative to the root font size), em and % (relative to the parent's font size), keywords like small or x-large, and clamp() for fluid sizes (Phase 3). Prefer rem for most text: people who raise the default font size in their browser settings then get bigger text everywhere, which px on the root would block.

  2. 2

    font-weight sets thickness, from 1 to 1000. normal is 400 and bold is 700; common steps are 300 (light), 500 (medium), 600 (semibold) and 900 (black). A weight only looks different if the font has that face (or is a variable font). bolder and lighter are relative to the parent: bolder on 400 gives 700, and on 700 gives 900.

  3. 3

    font-style makes text italic (a separately designed slanted face), oblique (the regular face, slanted) or normal. If the font has no italic face, the browser synthesises one by slanting the regular letters, and the same for missing bold. font-synthesis: none turns that faking off, which matters for scripts like Chinese where fake bold or italic hurts readability.

  4. 4

    line-height sets the height of each line box: the space a line of text takes, with the extra space split equally above and below the letters. normal is roughly 1.2 (it depends on the font). For body text, about 1.5 reads well. Values can be a unitless number (1.5, meaning 1.5 × this element's own font size), a length (24px, 1.5em, 1.5rem) or a percentage.

  5. 5

    Always prefer a unitless line height. It is inherited as the *number*, so each child multiplies it by its own font size. A length like 1.5em or 150% is calculated once on the parent and inherited as a fixed pixel value: a child with bigger text gets the parent's small line height, and its lines overlap.

  6. 6

    The font shorthand sets several properties at once: font: italic 700 1.25rem/1.5 Georgia, serif; (style, weight, size / line-height, family). font-size and font-family are required, in that order at the end. Every font property you leave out is reset to its initial value, including line-height (back to normal). The measure (line length) should be about 45–75 characters: max-width: 65ch on a text column does that, since ch is the width of the 0 character.

Explain it without notes

01

Why is a unitless line-height safer than 1.5em or 150%?

02

What does the font shorthand require, and what is the danger of using it?

03

What do bolder and lighter do, and why might font-weight: 600 look the same as 700?

04

What is a readable measure, and how do you set it in CSS?

Practice

01

Style an article: base text 1.125rem with line height 1.6, headings at line height 1.2, and lines no longer than 70 characters.

02

Rewrite these four declarations as one font shorthand: font-style: italic; font-weight: 600; font-size: 1.25rem; line-height: 1.4; with the family Georgia, serif.

03

A <small> inside a paragraph has font-size: 0.8em and the paragraph is 20px. How big is the small text? What if it were 0.8rem?

Trade-offs

  • ↔

    The font shorthand is compact but resets everything you omit; longhands are longer but change only what you name.

  • ↔

    Narrow measures read well but need more vertical scrolling; wide layouts fit more content but tire the eye. Use the width for side-by-side content, not for longer lines.

Done when you can

  • I can set font sizes in rem and explain why that respects user settings.

  • I can use numeric weights and bolder/lighter, and know when they look different.

  • I know the difference between italic, oblique and synthesised styles.

  • I always use a unitless line-height and can explain why.

  • I can write the font shorthand and know what it resets.

  • I can limit line length with max-width in ch.