Fluid typography with clamp() and type scales
Build a modular type scale, make it fluid with CSS clamp(), and keep text zoomable for accessibility.
A headline that looks right on a laptop is often too large on a phone and too small on a wide monitor. The traditional fix is media queries that jump between fixed sizes at breakpoints. Modern CSS offers a smoother approach: sizes that scale continuously with the viewport, within limits you choose, built on a consistent scale of sizes. This guide covers both halves, the type scale and the fluid sizing, and the accessibility rule that is easy to break along the way.
Start with a type scale
A modular type scale multiplies a base size by a fixed ratio for each step up. With a 16px base and a ratio of 1.25 (a “major third”), the steps are 16, 20, 25, 31.25, 39.06, and 48.83 pixels. With an 18px base and 1.333 (a “perfect fourth”), they are 18, 24, 32, 42.6, and 56.8. The typography scale tool previews a scale with your own sample text and exports it as CSS custom properties.
Choosing the ratio sets the character of the design:
- 1.125–1.2: subtle steps, suited to dense interfaces, dashboards, and documentation.
- 1.25–1.333: balanced, suited to most websites and articles.
- 1.5–1.618: dramatic, suited to editorial layouts and landing pages with few heading levels.
A scale gives consistency. Instead of choosing 22px here and 27px there, every size comes from the same system, which makes the hierarchy of headings obvious at a glance.
Make it fluid with clamp()
CSS clamp(minimum, preferred, maximum) returns the preferred value, but never less than the minimum or more than the maximum. For type, the preferred value is a linear function of the viewport width. Say a page title should be 32px on a 375px phone and 56px on a 1440px desktop. The CSS clamp calculator produces:
font-size: clamp(2rem, 1.471831rem + 2.253521vw, 3.5rem);The maths is a straight line through two points. The slope is (56 − 32) ÷ (1440 − 375) = 0.022535 pixels per pixel of viewport, which is 2.2535vw. The intercept is 32 − 0.022535 × 375 = 23.55px, or 1.4718rem. Below 375px the size stays at 2rem, and above 1440px at 3.5rem. In between it scales smoothly, with no breakpoints to maintain.
Combine the two ideas by giving each step of the scale a smaller size for mobile and a larger one for desktop. Many teams use a smaller ratio on mobile, such as 1.2, and a larger one on desktop, such as 1.333, so headings do not overwhelm small screens.
Do not break zoom
WCAG success criterion 1.4.4 requires that text can be resized to 200% without loss of content or function. Pure viewport units break this. A font size of 4vw ignores the user’s browser font-size setting and barely responds to zoom. The fix is to keep a rem component in every fluid size, as the clamp calculator does, so the text still responds to the reader’s preferences.
Test every fluid type setup in three ways:
- Zoom the browser to 200% and check that text grows and reflows.
- Increase the browser’s default font size, for example from 16px to 24px, and check that body text follows.
- Resize the window from narrow to wide and check intermediate sizes, such as tablets.
Body text: keep the range small
Fluid sizing is most useful for headings and hero text, where the difference between mobile and desktop is large. Body text reads best between about 16px and 20px on any screen, so a modest range such as 16px to 18px is plenty. More important for reading comfort are line length, around 60–75 characters per line, and line height, around 1.5 for body text and tighter for large headings.
Putting it together
- Choose a base size (16–18px) and a ratio.
- Generate the scale and assign steps to text roles.
- For headings, choose mobile and desktop sizes from the scale and generate a clamp() for each.
- Store the results as CSS custom properties or design tokens.
- Check contrast for every text colour. See the colour contrast guide.
