Guide
Web typography checklist: font size, line height and type scale for sites you build with AI
A practical web typography checklist: type scale, fluid font sizes with clamp(), line length, line height, contrast and text-wrap, with CSS and Tailwind examples and a prompt for your agent.
An agent can put together a landing page in about a minute, and at first sight everything looks fine. Zoom in on the text and the truth shows: five grays that differ by a hair, headlines wrapping so a single word sits alone, paragraph copy spanning a wide monitor, prices that slide around with every update. Sorting this out needs no designer, only a compact set of rules that you or your agent work through step by step. Here comes that set, with values you can take as they are.
1. Choose one or two fonts and load every weight you use
For most projects a single well crafted family does the job. Bring in a second family for headings only when it adds genuine contrast in character.
- Load the weights you actually use. Declaring just a regular file and then styling with
font-weight: 700makes the browser synthesize the bold, and it comes out smeared. A variable font holds every weight in one file. - Check the character set. The file has to contain umlauts, accented letters, currency symbols and the dash characters your copy uses.
- Give it a sensible fallback:
font-family: "Your Font", system-ui, sans-serif;
Hosting the font files yourself is covered in How to self-host web fonts.
2. Set a type scale instead of picking sizes by feel
A type scale is a fixed, short list of sizes. A modular scale produces it by starting from a base size and multiplying by one ratio over and over. Ratios you meet often are 1.2 (minor third), 1.25 (major third) and 1.333 (perfect fourth). Tighter ratios fit dense apps and dashboards, bigger ones fit marketing pages with oversized headlines.
Starting from a 16 px base with a ratio of 1.25 you end up with:
:root {
--text-sm: 0.8rem; /* 12.8 px */
--text-base: 1rem; /* 16 px */
--text-h4: 1.25rem; /* 20 px */
--text-h3: 1.563rem; /* 25 px */
--text-h2: 1.953rem; /* 31.25 px */
--text-h1: 2.441rem; /* 39 px */
--text-display: 3.052rem; /* 48.8 px */
}
Write font sizes in rem, not px. Browsers start from 16 px, and rem respects the font size a reader sets in their own browser, while px disregards it in some browsers.
Tailwind arrives with its own scale (text-base is 1rem, text-xl 1.25rem). Whichever route you take, settle on five or six steps and use nothing else.
3. Make large text fluid with clamp()
Headlines tuned on a laptop are often oversized on a phone. clamp(minimum, preferred, maximum) lets a size scale along with the viewport and stop at both ends.
The h1 below starts at 2rem (32 px) on a 360 px wide screen and tops out at 3.5rem (56 px) once the viewport reaches 1280 px:
h1 {
font-size: clamp(2rem, 1.413rem + 2.609vw, 3.5rem);
}
h2 {
font-size: clamp(1.5rem, 1.207rem + 1.304vw, 2.25rem);
}
Two rules keep it accessible:
- **Always mix
reminto the preferred value.** A size built purely fromvwrefuses to scale when someone zooms, since zooming shrinks the viewport. WCAG 1.4.4 calls for text that can be resized to 200 percent. - Keep the maximum at most 2.5 times the minimum. The guidance on web.dev points out that under this ratio, resizing text to 200 percent remains reachable even with the browser fully zoomed in.
Fluid sizing barely matters for body text. Going from 1rem on phones to 1.125rem on large screens is plenty: clamp(1rem, 0.951rem + 0.217vw, 1.125rem).
4. Keep lines between 45 and 75 characters
In The Elements of Typographic Style, Robert Bringhurst phrases it like this: a line anywhere from 45 to 75 characters is widely regarded as satisfactory, and 66 is frequently named as ideal. WCAG 1.4.8 (level AAA) caps it at 80 characters.
.prose {
max-width: 65ch;
}
In Tailwind that reads max-w-[65ch]. One thing to watch: 1ch equals the width of the zero digit in the active font rather than an average letter, so 65ch almost never fits exactly 65 characters. Set the width, then count one real line in the browser and tweak from there.
5. Give body text room: line height 1.5, headings tighter
Paragraphs read comfortably at a line height near 1.5. WCAG 1.4.8 (AAA) names "space-and-a-half" as the aim within paragraphs, and Tailwind's text-base defaults to exactly that. Big headlines want less, typically 1.1 to 1.25, because the space between large lines looks wider than it really is.
body { line-height: 1.5; }
h1, h2 { line-height: 1.15; }
Go with unitless numbers so the line height follows the font size. WCAG 1.4.12 also demands that nothing falls apart when a user pushes line height to 1.5, paragraph spacing to 2, letter spacing to 0.12 and word spacing to 0.16 times the font size. Text boxes with fixed heights are usually the reason it does.
6. Build hierarchy with size and weight, not color alone
When a paler gray is the only thing separating a heading from its label, the page goes flat and some readers overlook it. WCAG 1.4.1 states that color must never be the sole visual channel for conveying information. Combine a step on your type scale with a weight shift (say 400 for body, 600 for subheads, 700 for headings), then use spacing. Color may join on top of that.
7. Adjust letter spacing for capitals and big headlines
- All caps and small caps: Bringhurst advises letterspacing runs of capitals by 5 to 10 percent of the type size. That works out to
letter-spacing: 0.05emthrough0.1em, ortracking-widerandtracking-widestin Tailwind. - Large headlines: fonts spaced for reading sizes sit too loosely when blown up. Pull them in a little, roughly
-0.01emto-0.03em. Tailwind'stracking-tightequals-0.025em. The designer of Inter released a tracking formula for the font that lands near-0.022emat display sizes. - Body text: keep it on
normal.
Stick to em so the tracking scales along with the font size.
8. Meet the contrast ratios
WCAG 1.4.3 (level AA) calls for a contrast ratio of at least 4.5:1 on normal text and 3:1 on large text. Large here means 18 point and up, or 14 point bold and up, which WCAG translates to roughly 24 px and 18.5 px. The tighter AAA level (1.4.6) calls for 7:1 and 4.5:1.
Anchors on a white background: #999999 sits at 2.85:1 and fails, #767676 at 4.54:1 and clears AA, #595959 at 7:1 and clears AAA. Test pale gray captions and placeholders before anything else. The browser's developer tools report the ratio when you inspect a text element.
9. Use tabular numbers where digits line up
Plenty of fonts give the 1 less width than the 8, which makes prices, tables and counters slide sideways whenever values update. Tabular figures assign one shared width to every digit:
table, .price, .timer {
font-variant-numeric: tabular-nums;
}
In Tailwind: tabular-nums. It works only when the font ships the OpenType feature tnum, so look it up in your font's feature list.
10. Use text-wrap: balance for headings and pretty for paragraphs
h1, h2, h3 { text-wrap: balance; }
p { text-wrap: pretty; }
- **
balance** distributes a heading evenly across its lines, so a long first line will not be chased by one lone word. Chrome and Edge released it in version 114, Firefox in 121 and Safari in 17.5. Browsers balance only short blocks: up to six lines in Chromium and ten in Firefox. - **
pretty** switches body text to a slower line breaking algorithm, and its main effect is preventing a single word on the final line. Chrome and Edge have had it since 117, Safari since 26. Browsers without support simply wrap as usual, which means you can safely add it.
In Tailwind these are text-balance and text-pretty.
11. Check the mobile sizes
- Body text at least 16 px (1rem). Safari on iPhones zooms into any form field whose text is 15 px or smaller, which is why inputs need 16 px too.
- No text below about 12 px. For native iOS apps, Apple's own guidelines set 17 pt as the default body size and 11 pt as the floor.
- Test at 200 percent zoom as well as with a large system text setting. Nothing may overlap or be clipped.
The whole checklist in Tailwind v4
With Tailwind v4, declare the scale, line heights, tracking and weights inside @theme, so each utility carries the correct values:
@import "tailwindcss";
@theme {
--font-sans: "Your Font", system-ui, sans-serif;
--text-base: 1rem;
--text-base--line-height: 1.5;
--text-h2: clamp(1.5rem, 1.207rem + 1.304vw, 2.25rem);
--text-h2--line-height: 1.2;
--text-h2--letter-spacing: -0.01em;
--text-h2--font-weight: 600;
--text-display: clamp(2rem, 1.413rem + 2.609vw, 3.5rem);
--text-display--line-height: 1.1;
--text-display--letter-spacing: -0.02em;
--text-display--font-weight: 700;
}
<h1 class="text-display text-balance">Your headline</h1>
<p class="max-w-[65ch] text-pretty">Body copy...</p>
Under Tailwind v3, the identical values live in theme.extend.fontSize inside tailwind.config.js, for example display: ["clamp(2rem, 1.413rem + 2.609vw, 3.5rem)", { lineHeight: "1.1", letterSpacing: "-0.02em", fontWeight: "700" }].
Let your agent apply the checklist
Drop this into Claude Code, Cursor, Codex, Lovable or v0:
Prompt for your agent
Audit and fix the typography of this project: define one type scale (base 1rem, ratio 1.25) and replace all other font sizes with it, use rem not px, make headings fluid with clamp() that mixes rem and vw with a max no more than 2.5 times the min, limit text blocks to 65ch, set body line-height 1.5 and headings 1.1 to 1.25, build hierarchy with size and weight instead of color alone, add letter-spacing 0.05em to 0.1em on all-caps labels and slightly negative tracking on large headings, make every text color meet WCAG AA contrast (4.5:1, large text 3:1), use tabular-nums for prices, tables and counters, add text-wrap: balance to headings and pretty to paragraphs, keep body text and inputs at 16px or more on mobile. Show me a list of every change and every contrast value you measured.
Afterwards, open the site on a phone, zoom in to 200 percent and read one long page from top to bottom.
Questions people ask
What is the best font size for body text on a website? The browser default of 16 px (1rem) is the common minimum, and anywhere from 16 to 18 px serves most sites.
What line height should I use for web text? Around 1.5 in paragraphs, and about 1.1 to 1.25 on large headings. Choose unitless numbers so they follow the font size.
Which type scale ratio should I use? Go with 1.2 or 1.25 when your app or content site has many levels, and 1.333 or higher on landing pages that want strong contrast between headline and text.
Is fluid typography with clamp() accessible? It is, provided the preferred value contains rem and the maximum stays within 2.5 times the minimum. Verify at 200 percent zoom.
Can I use text-wrap: pretty today? Yes. Browsers without support fall back to normal wrapping, so nothing breaks.
The last item on the list: a font of your own
When scale, spacing and contrast all sit right, the font is what remains to set your project apart. Many AI-built sites gravitate toward the same handful of popular fonts, so even careful typography can feel familiar. The step beyond this checklist is a typeface nobody else has, your own handwriting in type. That is the thing we are building at MakeFont: your agent designs a font for your project, and you apply it with every rule above. It is in development, and early access is open. Read more in What is MakeFont.