Build a fluid type scale with clamp() that still passes zoom

Set your sizes for a small and a large screen and get a clamp() for every step, a live preview at any width, a zoom check against WCAG 1.4.4, and CSS, Tailwind v4, Tailwind v3, SCSS or JSON to copy.

  • Free, no sign-up
  • Runs in your browser: Nothing you paste or drop leaves your device.

Updated 18 October 2026

Make
Screens
px
px
Sizes
px
px
Steps
px16px unless your CSS changes html's font size.

Preview

  1. step-5 47.37pxDesign that reads well on every screen
  2. step-4 38.56pxDesign that reads well on every screen
  3. step-3 31.4pxDesign that reads well on every screen
  4. step-2 25.58pxDesign that reads well on every screen
  5. step-1 20.85pxDesign that reads well on every screen
  6. step-0 17pxDesign that reads well on every screen
  7. step--1 13.87pxDesign that reads well on every screen
  8. step--2 11.32pxDesign that reads well on every screen

The scale

Every step can zoom to twice its size, so the scale passes WCAG 1.4.4.

StepSmallestLargestclamp()Zoom
step-539.81px54.93pxclamp(2.4883rem, 2.1734rem + 1.3999vw, 3.4332rem)Passes
step-433.18px43.95pxclamp(2.0736rem, 1.8493rem + 0.997vw, 2.7466rem)Passes
step-327.65px35.16pxclamp(1.728rem, 1.5716rem + 0.6952vw, 2.1973rem)Passes
step-223.04px28.13pxclamp(1.44rem, 1.3341rem + 0.4708vw, 1.7578rem)Passes
step-119.2px22.5pxclamp(1.2rem, 1.1312rem + 0.3056vw, 1.4063rem)Passes
step-016px18pxclamp(1rem, 0.9583rem + 0.1852vw, 1.125rem)Passes
step--113.33px14.4pxclamp(0.8333rem, 0.8111rem + 0.0988vw, 0.9rem)Passes
step--211.11px11.52pxclamp(0.6944rem, 0.6859rem + 0.0379vw, 0.72rem)Passes

Code

Code
/* fluid type from 360px to 1440px screens, root 16px */
:root {
  --step--2: clamp(0.6944rem, 0.6859rem + 0.0379vw, 0.72rem);
  --step--1: clamp(0.8333rem, 0.8111rem + 0.0988vw, 0.9rem);
  --step-0: clamp(1rem, 0.9583rem + 0.1852vw, 1.125rem);
  --step-1: clamp(1.2rem, 1.1312rem + 0.3056vw, 1.4063rem);
  --step-2: clamp(1.44rem, 1.3341rem + 0.4708vw, 1.7578rem);
  --step-3: clamp(1.728rem, 1.5716rem + 0.6952vw, 2.1973rem);
  --step-4: clamp(2.0736rem, 1.8493rem + 0.997vw, 2.7466rem);
  --step-5: clamp(2.4883rem, 2.1734rem + 1.3999vw, 3.4332rem);
}

A type scale is one line of a design system

I design systems in Figma and build them in code, so the scale in the file is the scale in production.

What fluid typography is

Fluid type grows with the screen instead of jumping at breakpoints. A heading might be 32px on a phone and 56px on a laptop, and every width in between gets a size on the straight line between them. CSS does it in one line with clamp(): a smallest size, a preferred size that mixes rem and vw, and a largest size.

A type scale makes it systematic. Pick a base size and a ratio for small screens and another pair for large ones, and every step of the scale (small print, body, the headings) gets its own clamp(). Using a smaller ratio on phones and a larger one on desktops keeps headings from overwhelming a small screen.

How the clamp() value is worked out

For each step, the tool takes its size on the smallest screen and on the largest, and draws a line between them:

  • slope = (largest size minus smallest size) divided by (largest screen minus smallest screen)
  • intercept = smallest size minus slope times smallest screen
  • preferred value = intercept in rem, plus slope times 100 in vw

Then clamp() holds the size at the smaller and the larger of the two sizes, so it never shrinks below one or grows past the other. A step that gets smaller on large screens works too: the bounds swap, and the vw part turns negative.

Fluid type and WCAG zoom

WCAG 1.4.4 asks that text can be resized to 200% without loss. With fluid type that isn't automatic: when someone zooms in, the rem part of the size grows but the vw part doesn't, so a size made mostly of vw can't reach twice its size. This is the issue Maxwell Barvian set out in Smashing Magazine.

The tool checks every step on every screen from 320 to 3840 pixels: browser zoom goes up to 500%, so a step passes where some zoom level reaches twice the size it has at 100%. A useful rule of thumb from OddBird agrees with the check: a largest size no more than about 2.5 times the smallest passes. When a step fails, the table says on which screen widths.

Tailwind, CSS variables and the rest

Copy the scale in the form your project uses. CSS writes custom properties on :root. Tailwind v4 writes --text-* variables in @theme, so text-step-3 or text-h1 works as a utility. Tailwind v3 writes the fontSize part of tailwind.config.js. SCSS writes variables, and JSON writes each step's sizes, clamp() and zoom result for a design token pipeline.

Working with design tokens already? The design tokens to Tailwind converter takes a whole token file.

Picking a scale

A ratio of 1.2 (minor third) suits interfaces and long text on phones; 1.25 (major third) and 1.333 (perfect fourth) give clear headings on larger screens; 1.5 and above suit editorial pages with few, large headings. Keep the body text at 16px or more on phones, and check the preview at the widths your visitors use. A type scale is one line of a design system; the rest is what I build as a design engineer.

Questions people ask

  • Use clamp(smallest, preferred, largest), where preferred mixes rem and vw, like clamp(1rem, 0.8333rem + 0.8333vw, 1.5rem). Enter your sizes and screens here and copy the value.
  • It can be. The risk is browser zoom: the vw part of a size doesn't grow when people zoom in. Keep the vw share modest, and check each step with the zoom column here, which tests WCAG 1.4.4 on screens from 320 to 3840 pixels.
  • rem follows the visitor's font size setting and grows with zoom; px ignores the setting. Writing the bounds and the base of the preferred value in rem keeps the scale respectful of both.
  • Copy the Tailwind v4 output into your main CSS file after @import "tailwindcss". Each step becomes a --text-* variable, so classes like text-step-2 or text-h1 use the fluid size.
  • A common pair is 360px for the smallest phone you design for and 1440px for a typical laptop. Below and above them the sizes hold still.
  • For type sizes, mostly yes: one clamp() per step covers every width. You may still change layout or line length at breakpoints.

Need more than a free tool?

I design and build products around jobs like this one. Start with a free 30 minute call, then get one written scope and one fixed quote.

Book a free intro call