Text is most of what people come to a web page for, so it has to be easy to read everywhere. A 64-pixel heading that looks bold and confident on a laptop can take up half the screen on a phone, and lines of body text that stretch across a wide monitor are tiring to follow. Responsive typography adjusts sizes, spacing and line lengths so reading feels comfortable at every width.
There are two parts to getting it right. The first is choosing the right units: rem for font sizes so text respects the reader's browser settings, unitless line-height, and ch for line length. The second is scaling: using clamp() to make headings and spacing grow smoothly between a minimum and a maximum, instead of jumping at breakpoints.
In this lesson you'll set up a solid base, build a fluid type scale, keep paragraphs to a readable width, and use newer properties such as text-wrap: balance for tidy headings. You already know the font properties from CSS fonts and the maths from calc() and clamp(); here you'll put them to work.
Use rem for font sizes
Browsers have a default font size, usually 16px, and readers can change it in their settings. rem units are relative to that root size:
| Value | With the default 16px | If the reader sets 20px |
|---|---|---|
1rem | 16px | 20px |
1.25rem | 20px | 25px |
2rem | 32px | 40px |
If you write font-size: 16px, you override the reader's choice. Using rem keeps text accessible. Avoid setting html { font-size: 62.5%; } just to make maths easier; it shrinks every unstyled element and makes third-party widgets tiny.
Fluid sizes with clamp()
h1 { font-size: clamp(2rem, 1.2rem + 3.5vw, 3.5rem); }
h2 { font-size: clamp(1.5rem, 1.1rem + 2vw, 2.25rem); }
p { font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem); }- The first value is the minimum (phones), the last is the maximum (wide screens).
- The middle value mixes
remandvw, so the size grows with the screen but still responds to zoom and the reader's font setting. - Headings change most; body text changes only a little.
A type scale is a set of sizes that relate to each other, such as each heading being 1.25 times the size below. Store your scale in variables like --step-0 to --step-4, and use them everywhere.
Line length and line height
| Property | Recommendation | Why |
|---|---|---|
max-width on text | 60ch to 75ch | Long lines make it hard to find the next line |
line-height | 1.5 to 1.7 for body, 1.1 to 1.25 for headings | Big headings need less space between lines |
margin between paragraphs | about 1em to 1.5em | Clear separation without big gaps |
letter-spacing | Slightly negative on large headings, slightly positive on small caps | Fine-tunes the look |
ch is the width of the "0" character in the current font, so max-width: 65ch keeps lines to about 65 characters whatever the font size. Use unitless line heights such as 1.6, so the spacing scales with each element's font size.
Tidier wrapping
text-wrap: balancespreads a heading's words evenly across its lines, avoiding one long line followed by a single word.text-wrap: prettyavoids leaving a single short word alone on the last line of a paragraph.hyphens: autowith alangattribute on the page breaks long words in narrow columns.overflow-wrap: anywherestops long URLs from overflowing on phones.
CSS Responsive Typography Syntax
Responsive type
:root {
--step-0: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
--step-2: clamp(1.5rem, 1.1rem + 2vw, 2.25rem);
--step-4: clamp(2.25rem, 1.4rem + 4vw, 3.75rem);
}
body { font-size: var(--step-0); line-height: 1.6; }
h1 { font-size: var(--step-4); line-height: 1.1; text-wrap: balance; }
.prose { max-width: 65ch; }CSS Responsive Typography Summary
- Use
remfor font sizes so text follows the reader's settings. clamp(min, rem + vw, max)makes fluid sizes that still respond to zoom.- Keep text columns to about
60chto75chwide. - Use unitless line heights: around 1.6 for body text and 1.2 for headings.
text-wrap: balancetidies headings;prettytidies paragraph endings.
CSS Responsive Typography Examples
Each example runs in the page. Edit the code and press Run to see what changes.
A fluid type scale
Drag the result panel wider and narrower. The headings scale smoothly.
<article class="prose">
<h1>Planting a winter vegetable patch</h1>
<h2>Choose hardy crops</h2>
<p>Kale, leeks, winter cabbage and broad beans all cope with frost. Sow them in late summer so they're well established before the cold arrives.</p>
</article>:root {
--step-0: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
--step-2: clamp(1.4rem, 1.1rem + 1.5vw, 2rem);
--step-4: clamp(1.9rem, 1.2rem + 3.5vw, 3.25rem);
}
.prose { font-family: Georgia, serif; font-size: var(--step-0); line-height: 1.6; }
.prose h1 { font-size: var(--step-4); line-height: 1.1; margin: 0 0 0.4em; text-wrap: balance; }
.prose h2 { font-size: var(--step-2); line-height: 1.2; margin: 1em 0 0.3em; }Line-by-line explanation
- Lines 1 to 5The scale is defined once as variables.
- Line 7Body text grows only slightly between phones and desktops.
- Line 8The main heading changes the most, with tight line height and balanced lines.
Readable line length
<div class="wide"><p>Without a limit, this paragraph stretches across the whole container. On a large monitor, lines this long make it hard for your eyes to find the start of the next line, so reading slows down.</p></div>
<div class="limited"><p>With a maximum width of about 60 characters, lines are comfortable to read. Your eyes travel a short distance and find the next line easily, even on a very wide screen.</p></div>div { font: 17px/1.6 sans-serif; padding: 10px; margin-bottom: 10px; border-radius: 8px; }
.wide { background: #fee2e2; }
.limited { background: #dcfce7; }
.limited p {
max-width: 60ch;
}Line-by-line explanation
- Line 6The paragraph is never wider than about 60 characters, whatever the screen size.
balance and pretty wrapping
Narrow the panel to see the difference in the headings.
<h2 class="plain">Everything you need to know about fluid typography in modern CSS</h2>
<h2 class="balanced">Everything you need to know about fluid typography in modern CSS</h2>
<p class="nice">A long paragraph that uses text-wrap: pretty avoids leaving one lonely word on its final line, which makes blocks of text look more even.</p>h2, p { font-family: sans-serif; max-width: 420px; }
h2 { font-size: 1.6rem; line-height: 1.15; }
.plain { color: #9ca3af; }
.balanced { text-wrap: balance; }
.nice { text-wrap: pretty; line-height: 1.6; }Line-by-line explanation
- Line 4Normal wrapping fills each line, which can leave one short word on the last line.
- Line 5Balanced wrapping makes lines a similar length.
- Line 6Pretty wrapping avoids a single orphaned word.
Common CSS Responsive Typography Mistakes
Pixel font sizes everywhere
body { font-size: 16px; }
h1 { font-size: 40px; }body { font-size: 1rem; }
h1 { font-size: 2.5rem; }Pixel sizes ignore the reader's preferred font size.
vw-only font sizes
h1 { font-size: 5vw; } /* tiny on phones, huge on monitors, ignores zoom */h1 { font-size: clamp(2rem, 1rem + 4vw, 3.5rem); }Line height with units
body { line-height: 24px; } /* headings inherit 24px and overlap */body { line-height: 1.5; }A unitless value is multiplied by each element's own font size.
CSS Responsive Typography in Real Projects
Typography on real sites
Publications such as The Guardian and Medium keep article text around 65 to 70 characters wide with generous line height. Design systems define fluid type scales with clamp(), often generated by tools like Utopia. Chrome and Firefox support text-wrap: balance, and many blogs now use it on headings. Accessibility audits test text at 200% zoom, and sites using rem pass easily.
CSS Responsive Typography Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Keep the paragraph to about 65 characters per line.
.prose {
max-width: 65;
}
ch is based on the width of the "0" character.Why use rem for font sizes?
Which line height suits body text best?
What does text-wrap: balance do?
The heading should use clamp() between 2rem and 3rem, the paragraph should use a unitless 1.6 line height, and lines should be at most 60ch. Fix it.
<h1 class="t">Fresh pasta at home</h1>
<p class="b">Mix flour and eggs, knead for ten minutes, rest, then roll thin.</p>.t { font-size: 6vw; }
.b { line-height: 26px; max-width: 900px; }- Heading uses clamp between 2rem and 3rem
- Heading size is within limits
- Unitless line height
- Lines limited to 60ch
CSS Responsive Typography Quiz
5 questions to check what you learned.
What is 1.5rem with the default browser font size?
- 15px
- 1.5px
- 24px
- 32px
Why add rem to a vw value in clamp's middle value?
- Because vw doesn't work alone
- So text still grows when the reader zooms or changes their font size
- To make it smaller
- For older browsers
What is a comfortable line length for body text?
- 20 to 30 characters
- 150 characters
- As wide as the screen
- About 60 to 75 characters
Why should line-height usually be unitless?
- Units aren't allowed
- It's faster
- Each element multiplies it by its own font size
- It removes spacing
What does text-wrap: pretty improve?
- Avoiding a single word left alone on a paragraph's last line
- Heading font weight
- Letter spacing
- Underline style
CSS Responsive Typography Challenge
A readable article
- Set
.articlefont-size: 1remandline-height: 1.6 - Limit
.articletomax-width: 65ch - Give
.article h1afont-sizeofclamp(2rem, 1.2rem + 3vw, 3rem),line-height: 1.1andtext-wrap: balance
<article class="article">
<h1>A beginner's guide to sourdough bread</h1>
<p>Sourdough uses wild yeast from a starter instead of packet yeast. It takes longer, but the flavour is deeper and the crust crisper.</p>
</article>.article { font-family: Georgia, serif; }
- 1rem body text with 1.6 line height
- Max width of 65ch
- Fluid heading within limits
- Tight balanced heading