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.
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.
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.
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.
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.
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.
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
Predict the overlap
In the first example, change
.em { line-height: 1.5em; }to150%. Predict the big child's line height before running. It is still24px: a percentage is also computed once on the parent. - 2
Fix the shorthand
In the second example, move
line-height: 2;below thefontline, or put it into the shorthand asfont: 18px/2 Georgia, serif;. Predict the first console line. It becomes36px(2 × 18px). - 3
Find a comfortable measure
In the third example, try
max-width: 40ch, then90ch. Read a few lines of each. Most people find somewhere around 60–70 easiest.
Code & diagrams
Both parents compute 24px. Only the unitless one lets the big child compute its own line height.
Preview
Console
Nothing logged yet.Expected console output
em parent: 24px | big child: 24px
unitless parent: 24px | big child: 48px`font` came after `line-height` and silently set it back to `normal`. `bolder` steps up from the parent's weight: 400 → 700 → 900.
Preview
Console
Nothing logged yet.Expected console output
.a line-height: normal
outer b: 700
inner b: 900`ch` is the width of the `0` character in the current font, so the limit grows and shrinks with the text size.
Preview
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.
Break #2
Shorthand missing the family
Write font: bold 20px; on a heading.
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 whysup { 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(fromtext-box-trim/text-box-edge) trims that space so text aligns optically with icons and boxes; check support before relying on it. - ▸
font-weightnumbers 1–1000 and fractional values (like550) are part of CSS Fonts Level 4; they only render differently with variable fonts.bolder/lighteruse 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
font-sizesets the size of the letters. The browser default is16px(the keywordmedium). You can usepx,rem(relative to the root font size),emand%(relative to the parent's font size), keywords likesmallorx-large, andclamp()for fluid sizes (Phase 3). Preferremfor most text: people who raise the default font size in their browser settings then get bigger text everywhere, whichpxon the root would block. - 2
font-weightsets thickness, from1to1000.normalis400andboldis700; common steps are300(light),500(medium),600(semibold) and900(black). A weight only looks different if the font has that face (or is a variable font).bolderandlighterare relative to the parent:bolderon400gives700, and on700gives900. - 3
font-stylemakes textitalic(a separately designed slanted face),oblique(the regular face, slanted) ornormal. If the font has no italic face, the browser synthesises one by slanting the regular letters, and the same for missing bold.font-synthesis: noneturns that faking off, which matters for scripts like Chinese where fake bold or italic hurts readability. - 4
line-heightsets the height of each line box: the space a line of text takes, with the extra space split equally above and below the letters.normalis roughly1.2(it depends on the font). For body text, about1.5reads 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
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.5emor150%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
The
fontshorthand sets several properties at once:font: italic 700 1.25rem/1.5 Georgia, serif;(style, weight, size/line-height, family).font-sizeandfont-familyare required, in that order at the end. Every font property you leave out is reset to its initial value, includingline-height(back tonormal). The measure (line length) should be about 45–75 characters:max-width: 65chon a text column does that, sincechis the width of the0character.
Explain it without notes
Why is a unitless line-height safer than 1.5em or 150%?
What does the font shorthand require, and what is the danger of using it?
What do bolder and lighter do, and why might font-weight: 600 look the same as 700?
What is a readable measure, and how do you set it in CSS?
Practice
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.
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.
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
fontshorthand 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
remand 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-heightand can explain why.I can write the
fontshorthand and know what it resets.I can limit line length with
max-widthinch.