Create clear visual hierarchy using weight, size, colour, spacing, and emphasis. Learn when and how to use bold, italic, uppercase, and colour contrast to guide readers through content.
Typographic hierarchy is the visual system that tells readers which information matters most, which is supporting, and which is peripheral. Without hierarchy, all text competes for equal attention and readers must work to find what they need. With well-executed hierarchy, the eye moves naturally through a page from most important to least. This lesson gives you the specific CSS techniques to build that guidance system.
Size is the most obvious hierarchy tool and the most overused. Rely on it for primary distinctions (heading vs body) but avoid using size alone for every level. Weight (font-weight) is extremely effective at small size ranges — a 400 vs 700 distinction at the same font size creates clear hierarchy without consuming vertical space. Colour and contrast create hierarchy without changing size or weight — a lighter grey for secondary text (contrast ratio 3:1) visually recedes relative to primary black text (contrast ratio 15:1 on white). Spacing creates hierarchy by grouping and separating — a heading close to its following content feels grouped; generous space above it creates a new section boundary. Style (italic, uppercase, small-caps) marks special roles like citations, labels, and metadata without changing the text flow. Effective hierarchy uses at most three of these tools simultaneously — using all five on the same element creates visual noise rather than emphasis.
1/* Hierarchy using size + weight */
2.primary { font-size: 1rem; font-weight: 700; color: #111; }
3.secondary { font-size: 1rem; font-weight: 400; color: #111; }
4.tertiary { font-size: 0.875rem; font-weight: 400; color: #6b7280; }
5
6/* Hierarchy using only weight + colour — same size */
7.data-label { font-size: 0.75rem; font-weight: 600; color: #374151; }
8.data-value { font-size: 0.75rem; font-weight: 400; color: #9ca3af; }In HTML, <strong> conveys strong importance (semantic bold) and <em> conveys stress emphasis (semantic italic). <b> and <i> are presentational — used for stylistic offset without semantic importance (book titles, technical terms, keywords). CSS font-weight: bold and font-style: italic are the visual counterparts. The critical implementation rule: always load the actual bold and italic font files. The browser synthesises fake bold by adding stroke width and fake italic by slanting the upright face — both look noticeably crude compared to true drawn variants. Declare both in @font-face with matching font-weight and font-style descriptors.
1/* Load real bold and italic files */
2@font-face {
3 font-family: 'Lora';
4 src: url('/fonts/lora-regular.woff2') format('woff2');
5 font-weight: 400;
6 font-style: normal;
7}
8@font-face {
9 font-family: 'Lora';
10 src: url('/fonts/lora-bold.woff2') format('woff2');
11 font-weight: 700;
12 font-style: normal;
13}
14@font-face {
15 font-family: 'Lora';
16 src: url('/fonts/lora-italic.woff2') format('woff2');
17 font-weight: 400;
18 font-style: italic;
19}
20
21/* Now strong and em render with real drawn variants */
22strong { font-weight: 700; } /* Uses lora-bold.woff2 */
23em { font-style: italic; } /* Uses lora-italic.woff2 */Using colour to create hierarchy is powerful but must satisfy WCAG contrast requirements. WCAG 1.4.3 requires a 4.5:1 contrast ratio for normal text (under 18pt / 24px) and 3:1 for large text (18pt+ / 24px+) against the background. For a white (#ffffff) background: #111111 is ~17.7:1 (primary text), #595959 is ~7:1 (body/secondary text), #767676 is ~4.54:1 (barely passes for normal text), #9ca3af is ~2.85:1 (fails for normal text — use only for decorative or large text). When building dark mode, these ratios must be recalculated for the dark background. Use a contrast checker tool (Accessible Colors, Contrast Ratio by Lea Verou) for every colour pair.
1:root {
2 /* Light mode: all ratios against #ffffff */
3 --text-primary: #111827; /* ~16.75:1 — headings */
4 --text-body: #374151; /* ~10.68:1 — body */
5 --text-secondary: #6b7280; /* ~4.63:1 — secondary, passes AA */
6 --text-disabled: #9ca3af; /* ~2.85:1 — disabled only, not readable text */
7}
8
9@media (prefers-color-scheme: dark) {
10 :root {
11 /* Dark mode: ratios against #111827 */
12 --text-primary: #f9fafb; /* ~16.0:1 */
13 --text-body: #e5e7eb; /* ~12.0:1 */
14 --text-secondary: #9ca3af; /* ~5.74:1 — passes AA */
15 --text-disabled: #6b7280; /* ~2.85:1 */
16 }
17}Heading spacing is one of the most common sources of visual incoherence. The key principle: a heading is more related to the content it introduces than to the content preceding it. Space above a heading should be greater than space below it. A common ratio is 3:1 (three times as much space above as below). Using margin-block-start and margin-block-end (logical properties) keeps the system direction-aware for RTL layouts. The em unit is ideal for heading margins because it scales with the heading's font size, maintaining proportional spacing at every level of the scale.
1/* Heading spacing system */
2:is(h1, h2, h3, h4, h5, h6) {
3 /* Default: 2.5× as much space above as below */
4 margin-block-start: 2em;
5 margin-block-end: 0.75em;
6 line-height: 1.2;
7 font-weight: 700;
8}
9
10/* First heading in a section: no top margin */
11:is(h1, h2, h3):first-child {
12 margin-block-start: 0;
13}
14
15/* Heading immediately after another heading */
16:is(h1, h2, h3, h4) + :is(h2, h3, h4) {
17 margin-block-start: 0.5em; /* Reduce gap between adjacent headings */
18}
19
20/* Paragraph after heading: slightly less than body paragraph gap */
21:is(h2, h3, h4) + p {
22 margin-block-start: 0; /* Heading margin-end handles the gap */
23}Over-emphasis is when so many elements are visually prominent that nothing is actually prominent — everything shouts, nothing leads. Common patterns to avoid: bold entire paragraphs (defeats the emphasis signal), using three or more colour values in the same content block (creates visual confusion rather than hierarchy), all-caps entire sentences of body text (severely reduces reading speed), italic text in long runs (italic is for short phrases, not paragraphs), and combining bold + italic + colour + size changes on a single element (the fourth emphasis tool adds nothing — remove one). The test: if you muted all emphasis (set everything to the same weight, size, and colour), would the content still make semantic sense? Emphasis should reinforce meaning, not substitute for it.
1/* Anti-pattern: over-emphasised paragraph */
2.bad-paragraph {
3 font-weight: 700; /* Bold entire block */
4 font-style: italic; /* Also italic */
5 color: #dc2626; /* Also red */
6 text-transform: uppercase; /* Also uppercase */
7 font-size: 1.25rem; /* Also larger */
8 /* Result: looks panicked, not important */
9}
10
11/* Correct: single purposeful emphasis tool */
12.callout {
13 font-size: 1.125rem; /* Slightly larger — one tool */
14 font-weight: 400; /* Not bold — let size do the work */
15 border-inline-start: 3px solid #2563eb; /* Visual marker */
16 padding-inline-start: 1rem;
17 color: inherit; /* Same colour as body */
18}A complete heading and body hierarchy with weight, colour, and spacing working together.
Next lesson covers pairing typefaces — the principles and CSS implementation for combining a display face with a body face coherently.
Your progress is saved in this browser, on this device only.