Media queries make values jump: 16px, then suddenly 20px, then 24px. Fluid values grow smoothly with the screen instead. In modern CSS, one line does it:
font-size: clamp(16px, calc(10.66667px + 1.48148vw), 32px); This post shows how to read declarations like this, gives you ready-made examples, and covers the mistakes that quietly break them.
How to read a clamp() declaration
clamp() takes three arguments:
clamp(minimum, preferred, maximum) - minimum: the value never goes below this (16px above)
- preferred: the part that changes with the viewport (
calc(… + …vw)) - maximum: the value never goes above this (32px above)
The example above means: 16px on a 360px screen, 32px on a 1440px screen, smooth growth in between, and it stays at 16px or 32px outside that range. No media queries needed.
The numbers in the middle look odd, but you don't need to touch them by hand. You decide the two endpoints, and the declaration follows from them.
Copy-paste examples
All of these scale between a 360px and a 1440px viewport.
Body text, 16px → 18px
font-size: clamp(16px, calc(15.33333px + 0.18519vw), 18px); Headline, 28px → 56px
font-size: clamp(28px, calc(18.66667px + 2.59259vw), 56px); Section spacing, 32px → 96px
padding-block: clamp(32px, calc(10.66667px + 5.92593vw), 96px); Grid gap, 12px → 32px
gap: clamp(12px, calc(5.33333px + 1.85185vw), 32px); Card corners, 12px → 24px
border-radius: clamp(12px, calc(8px + 1.11111vw), 24px); Values that shrink on wider screens
Fluid doesn't always mean "bigger on desktop". Here's card padding that is roomy on phones (24px) and tighter on wide multi-column layouts (12px), between 375px and 1440px:
padding: clamp(12px, calc(28.22535px - 1.12676vw), 24px); Note the minus before the vw part. That's what makes the value go down as the screen gets wider.
Three mistakes that break clamp()
1. Swapping min and max. The first argument must be the smaller value, even when it belongs to the wider screen. In the padding example, 12px comes first. If the minimum is larger than the maximum, clamp() always returns the minimum, and your value stops being fluid without any error.
2. No spaces around + and -. calc(10px+2vw) is invalid. calc(10px + 2vw) works. The browser drops the whole declaration if the spaces are missing.
3. Using px for text without thinking about it. Pixel values ignore the user's browser font-size setting: someone who set their default text to 20px still gets your 16px. For font-size, convert the px parts to rem (divide by 16) and leave the vw part as it is:
font-size: clamp(1rem, calc(0.66667rem + 1.48148vw), 2rem); For width, gap or border-radius, plain px is usually fine.
What clamp() can't do: opacity
Try to make opacity fluid and you'll hit a wall. opacity needs a plain number like 0.6, but anything with vw in it is a length, and CSS won't convert one into the other.
The workaround is a tiny JavaScript function that returns the value for the current viewport width. Fading an overlay from 0.4 on small screens to 0.8 on large ones:
function getResponsiveValue(viewportWidth) { const minViewport = 320; const maxViewport = 1980; const minValue = 0.4; const maxValue = 0.8; if (viewportWidth <= minViewport) return minValue; if (viewportWidth >= maxViewport) return maxValue; const progress = (viewportWidth - minViewport) / (maxViewport - minViewport); return minValue + (maxValue - minValue) * progress; } const overlay = document.querySelector('.hero-overlay'); const update = () => { overlay.style.opacity = getResponsiveValue(window.innerWidth); }; update(); window.addEventListener('resize', update); Browser support
clamp() and calc() with vw work in all current versions of Chrome, Edge, Firefox and Safari. No fallbacks needed unless you support very old browsers.
Generate your own
The examples above cover common cases, but your design has its own sizes and breakpoints. I built a small free tool for exactly that: wresp.com. Pick a property, enter the values you want on a narrow and a wide screen, and it gives you the clamp() declaration, or the JavaScript function for opacity. A live preview slider shows how the value behaves at every width in between.
It's a side project, so feedback is very welcome. What would you want from a fluid-value generator that other tools don't do? Let me know in the comments. 👇

![Why Object.keys(user) Returns string[], Not (keyof User)[]: TypeScript Means It](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2q4w48b9bzs43tynyhsf.png)