CSS clamp generator
Type scales with the viewport
Generated in your browser · nothing is uploaded
Builds a clamp() that moves a size linearly between two viewport widths; a small size at a small screen, a large size at a large one, and a straight line between them. Drag the preview to see the value at any width.
How to use the css clamp generator
The middle term of a clamp is nothing more exotic than the equation of a line through two points. Slope is the size difference divided by the width difference; the intercept is where that line would cross a viewport of zero width. Take the default here, 16px at 320px growing to 32px at 1280px. The slope is 16 ÷ 960, which is 0.016667 pixels of type per pixel of viewport, and a viewport pixel is one hundredth of a vw, so the slope becomes 1.667vw. The intercept is 16 − (320 × 0.016667), which is 10.667px, or 0.667rem at a 16px root. Put them together and you have clamp(1rem, 0.667rem + 1.667vw, 2rem). Every fluid-type clamp looks like an arbitrary pair of numbers for that reason: they are the two coefficients of a line, and nothing else.
Writing the intercept in rem rather than px is deliberate, and it is the part most hand-written clamps get wrong. A viewport unit answers to the window and to nothing else. It does not move when a reader raises their browser’s default font size, so a size built purely from vw quietly overrides a setting somebody chose on purpose. WCAG 1.4.4 requires that text can be resized up to 200 per cent without losing content or function, and a rem term keeps the reader’s setting inside the equation. The minimum and maximum are in rem here too, which matters even more: at the small and large ends of the range the value is pure rem, so their setting has full effect exactly where the text is smallest.
The function needs no calc() around that sum, and this surprises people who have written CSS for a while. clamp(), min() and max() are themselves maths functions, and each of their arguments is parsed as a calculation, so 0.667rem + 1.667vw is valid where it stands. It is also worth being precise about what the three arguments do: clamp(a, b, c) is defined as max(a, min(b, c)), so the value is held at the minimum below the range and at the maximum above it, and if you accidentally set a minimum larger than the maximum, the minimum wins.
Two cautions on choosing the range. A very steep slope makes text visibly jump while a window is dragged, and a very shallow one makes the whole exercise pointless; keeping the largest size under roughly twice the smallest avoids both. And the conversion here assumes a 16px root, which is the browser default. If your stylesheet sets html { font-size: 62.5% } to make a rem equal 10px, every rem figure generated here is wrong by a factor of 1.6, and that old trick is worth abandoning rather than compensating for.
What people use it for
- Sizing a heading that has to work at 375px and at 1440px
- Replacing three font-size media queries with one declaration
- Keeping fluid type responsive to a reader’s own browser font setting
- Working out the rem and vw coefficients behind a size range
- Scaling section padding or a gutter with the viewport rather than the text
Questions
Because it is the equation of a line. The rem term is the intercept and the vw term is the slope, and together they draw a straight line between your two endpoints.
Size difference divided by width difference, then multiplied by 100 to become a vw. Going from 16px to 32px across 320px to 1280px gives 16 ÷ 960 = 0.016667, so 1.667vw.
It is the intercept: the minimum size minus the slope times the minimum width. Here that is 16 − (320 × 0.016667) = 10.667px, which is 0.667rem at a 16px root.
A pixel intercept stops the value responding to the reader’s font-size setting, which is what WCAG 1.4.4 asks you to preserve. A rem keeps their choice in the equation.
No. clamp(), min() and max() parse each argument as a calculation already, so a sum can be written directly inside them.
The value is held flat. Below the smaller width it stays at the minimum and above the larger it stays at the maximum, so the line only ever applies between them.
The minimum wins, because clamp(a, b, c) is defined as max(a, min(b, c)) and the outer maximum has the final say.
Yes, which is the browser default. If your stylesheet resets the root to 10px with font-size: 62.5%, every rem figure generated here needs multiplying by 1.6.
Yes, on any length property. Section padding, gutters, gaps and border radii all take a clamp perfectly well. Only the preview here happens to be type.
Use vw when the element really does scale with the window. For a component that sits in a sidebar or a card, cqi measures the container instead, which is usually the size that should actually drive it.
For sizes, rarely; a clamp covers the whole range in one declaration. For layout changes, a column count, a reordered header, an element that disappears, they are still the right tool.