Sixteen pixels: that is the text size almost every browser applies to a web page by default. Yet most mockups stack seven or eight font sizes chosen by eye, with no logical link between them. A typographic scale puts things back in order: a single mathematical rule generates every size, from the smallest label to the largest heading. Here is how to build one step by step, without a generator that spits out unusable decimals.
Step 1: set the body size before any other decision
The classic mistake is to draw the big heading first, then shrink everything else to fit around it. You end up with body text that is too small and hard to read on mobile. Do the opposite: fix the size of the running text first, the one the visitor will read the longest.
A body of 16 to 18 pixels suits most content sites. Below 16, sustained reading tires the eye, especially on long paragraphs. The browser default stylesheet sets base text to 16 pixels, so starting from that value means respecting a setting the user may have customised in their preferences.
Two settings travel with this body text and shape everything else:
- Line height: around 1.5 times the text size for a paragraph, tighter for headings.
- Line length: aim for 45 to 75 characters per line. Beyond that, the eye struggles to find the start of the next line.
These two parameters decide reading comfort well before the choice of typeface. Once the body is locked, the whole system flows from it.
Step 2: pick a ratio that fits the context, not habit
A typographic scale multiplies the base size by a constant ratio to go up (headings) and divides it to go down (captions, labels). The larger the ratio, the more dramatic the gap between a heading and the running text. The trap is to reach for the same ratio out of reflex, without asking whether it serves the type of page.
These ratios borrow from musical intervals, which is where their names come from. The table below sets each one against its concrete use:
| Ratio | Common name | Visual contrast | Fitting context |
|---|---|---|---|
| 1.125 | Major second | Low | Dense interfaces, dashboards, apps |
| 1.200 | Minor third | Moderate | Blogs, media, long-form content |
| 1.250 | Major third | Marked | Marketing sites, product pages |
| 1.333 | Perfect fourth | Strong | Landing pages, portfolios |
| 1.500 | Perfect fifth | Very strong | Minimalist hero pages, posters |
The logic: the more information a page packs in at equal density, the lower the ratio should stay so headings do not crush everything. Conversely, a landing page with little text benefits from strong contrast that guides the eye from one block to the next. This visual hierarchy connects to the perception principles we break down in our studies of UX and UI laws: size is one of the first signals the brain processes to order a page.
Step 3: generate the sizes, round them, cap the count
With a base of 16 pixels and a ratio of 1.25, going up gives 20, then 25, then 31.25, then 39.06, and so on. Going down gives 12.8, then 10.24. These decimals are the main flaw of online generators: nobody willingly codes a 31.25 pixel margin, and those values break alignment with the rest of the mockup.
The fix comes down to three moves:
- Compute the raw series from the base and the ratio, without touching it.
- Round each value to the nearest multiple of your grid step (often 4 pixels): 31.25 becomes 32, 12.8 becomes 12.
- Cap the number of sizes at six or seven. Body, small text, and four to five heading levels cover almost every need.
Rounding onto the same grid as your margins and paddings keeps the whole thing coherent. If you already work with a steady vertical rhythm, this step happens naturally: it is the direct extension of a spacing system built on a grid that we apply to every mockup. Once rounded, save these values as reusable variables rather than retyping them by hand everywhere. Name them by role, not by size (a token like text-h2 rather than text-32), so a later tweak to the ratio does not leave you with a variable called 32 that now holds 30.
Here is an example of a final scale, ratio 1.25, base 16, rounded to a 4 pixel step:
- Caption / label: 12 px
- Small text: 14 px
- Body: 16 px
- Subheading: 20 px
- H3 heading: 24 px
- H2 heading: 32 px
- H1 heading: 40 px
One last habit makes the difference at build time: express these sizes in rem rather than fixed pixels. One rem equals the text size defined on the document root, which is 16 pixels by default. As a result, when a visitor raises the font size in their browser to read more easily, the whole scale grows proportionally, headings included. A scale in hard pixels ignores that setting and penalises people with low vision. The conversion is simple: divide each pixel value by 16, so 24 px becomes 1.5 rem and 40 px becomes 2.5 rem.
Step 4: make the scale fluid, then check the hierarchy
A scale frozen in pixels raises a problem: a 40 pixel H1 that feels commanding on a desktop turns oversized on a phone screen. Two approaches exist. The simplest redefines a few heading sizes inside a mobile media query. The most elegant uses the CSS clamp() function, which interpolates the size between a minimum and a maximum value based on screen width, with no visible breakpoint.
A declaration like font-size: clamp(2rem, 1.5rem + 2vw, 2.5rem) makes a heading vary continuously between 2 and 2.5 rem. The reference documentation details exactly how this function behaves on the MDN page for clamp(), a neutral and up-to-date source for pinning down the syntax. Reserve the fluid version for large headings: the body text is better left stable to preserve the line length calculated in step 1.
Once the scale is in place, check it on three points before signing off:
- Do two neighbouring levels stand apart at a glance? If an H2 and an H3 look alike, the ratio gap is too small or you have too many levels.
- Is the smallest size still legible on mobile? A 12 pixel caption is a reasonable floor, rarely worth crossing.
- Does the colour contrast keep up? A well-chosen size does not redeem a grey that is too light on a white background. These two settings are decided together, notably for the polished builds delivered by the top teams in our directory of web design agencies.
This last check ties typography back to accessibility: the hierarchy must hold up for a rushed reader as well as for a user who enlarges the page. Run it on real content, not lorem ipsum: a heading that looks balanced next to a single line often falls apart above a three-line paragraph, and only genuine copy reveals whether the smallest label survives at the bottom of a busy page.
The essentials for a typographic scale that lasts
A typographic scale is not a generator gimmick: it is a design decision that makes every page predictable and quick to roll out. To recap:
- Start from the body text (16 to 18 px), with a line height of about 1.5 and a line length of 45 to 75 characters.
- Choose the ratio by context: low for dense interfaces, high for high-impact pages.
- Round each size to your grid (often to a 4 px step) and stop at six or seven sizes.
- Make only the large headings fluid with
clamp(), keeping the body stable. - Check legibility and contrast before freezing the variables in your code.
Applied once, this method carries over to every project: you no longer redraw sizes case by case, you adjust a ratio and a base. That kind of invisible foundation is what separates a patched-together mockup from a site built to last.