Why is the declaration font-size: clamp(1rem, 1rem+2vw, 2rem) invalid CSS, and what is the minimal fix?
answer
- nothing about the value is semantically wrong
- the parser, not the layout algorithm
- signs and operators share characters
- whitespace around + and -
- invalid value drops the whole declaration
basics
~20 sCSS math grammar requires whitespace around the + and - operators, so 1rem+2vw fails to parse and the whole declaration is dropped. The fix is spacing alone: clamp(1rem, 1rem + 2vw, 2rem). No calc() wrapper is needed, because each clamp() argument is already a math expression.
solid answer
~40 sCSS parses `+` and `-` as part of a number's syntax as well as as operators, so the math grammar demands whitespace on both sides of them — `1rem+2vw` is ambiguous and simply fails to parse. An invalid value makes the browser discard the entire declaration, so the element silently falls back to its inherited or default `font-size` rather than showing an error. The fix is just spaces: `clamp(1rem, 1rem + 2vw, 2rem)`. Wrapping the middle argument in `calc()` is unnecessary, because every argument of `clamp()`, `min()` and `max()` is parsed as a calculation in its own right — and it would not help anyway, since the same whitespace rule applies inside `calc()`. The `*` and `/` operators do not need surrounding whitespace, though writing it anyway keeps the code consistent.
go deeper
Remember to put spaces around + and - inside calc(), clamp(), min() and max(). If a fluid value seems to do nothing at all, check the declaration for a missing space first.
Explain why the rule exists — a leading + or - is also part of a number's syntax, so whitespace disambiguates operator from sign — and note that each math-function argument is already a calculation, so calc() adds nothing.
Describe how CSS discards only the offending declaration with no console error, and how you would spot the symptom in review or devtools: a fluid value that never changes across viewport widths is almost always a parse failure, not a clamping one.
Push this class of silent failure into tooling rather than review habit — stylelint rules and build-time CSS parsing catch dropped declarations, and generating fluid values from tokens removes hand-written arithmetic from feature code altogether.
## The parsing rule In CSS math expressions — `calc()`, `min()`, `max()`, `clamp()` and friends — the `+` and `-` operators **must be surrounded by whitespace**. `1rem+2vw` and `1rem -2vw` are both parse failures. `*` and `/` carry no such requirement, so `2*1rem` and `100%/3` are legal, though most codebases space them anyway. The reason is that `+` and `-` are not only operators in CSS: they are also legal leading characters of a number. In `1rem -2vw` the token `-2vw` is a perfectly good negative length, so a parser reading the stream cannot tell whether you meant "one rem, minus two vw" or a malformed sequence of two values. Requiring whitespace on **both** sides removes the ambiguity: an operator always has space around it, a sign never does. ```css /* invalid — dropped */ font-size: clamp(1rem, 1rem+2vw, 2rem); width: calc(100%-2rem); /* valid */ font-size: clamp(1rem, 1rem + 2vw, 2rem); width: calc(100% - 2rem); width: calc(100%/3); /* division needs no spaces */ font-size: calc(2*1rem); /* multiplication needs none either */ ``` ## Why the failure is easy to miss CSS error handling discards at the smallest possible level. An invalid value invalidates that one declaration; the rest of the rule and the rest of the stylesheet survive. There is no console error for a bad declaration, and the element keeps whatever value the cascade gave it — usually the inherited size, which is often close enough to the intended one that nobody notices until a designer complains the type is not scaling. The practical tell is that a fluid value "does nothing at all" at every viewport width. A `clamp()` that is being clamped still *changes* between narrow and wide screens; a `clamp()` that never changes anywhere is usually a parse failure. Any devtools style panel will show the declaration struck through or simply absent. ## calc() is not required inside math functions Each argument of `min()`, `max()` and `clamp()` is defined as a calculation, so arithmetic is allowed directly: ```css font-size: clamp(1.125rem, 1rem + 0.5vw, 1.5rem); /* fine */ font-size: clamp(1.125rem, calc(1rem + 0.5vw), 1.5rem); /* also fine, just noisier */ ``` Both parse. Adding `calc()` is harmless but redundant, and critically it does **not** rescue a missing space — the whitespace rule applies identically inside `calc()`. Candidates who "fix" the bug by wrapping in `calc()` without adding spaces have not understood the failure. Math functions also nest freely: `clamp()` inside `calc()`, `min()` inside `minmax()`, `max()` inside `clamp()`. The whitespace rule holds at every level. ## Unit mixing is allowed; type mixing is not Mixing units of the same type is the entire point — `1rem + 0.5vw` is a length plus a length, and the browser resolves both to pixels at used-value time. What is not allowed is mixing *types*: adding a length to a bare number, or to an angle, makes the expression invalid. Multiplication has its own rule — at least one operand must be a plain number (`2 * 1rem` is valid, `1rem * 1rem` is not) — and in division the divisor must be a plain number. ## How to answer it in an interview Name the rule, name the consequence, give the fix: "`+` and `-` need whitespace on both sides because a leading sign is also part of a number's syntax; without it the value is invalid and the whole declaration is dropped silently. The fix is `clamp(1rem, 1rem + 2vw, 2rem)` — spaces, not `calc()`, since each argument is already a calculation."
- Do * and / have the same whitespace requirement?No. Only `+` and `-` require surrounding whitespace, because those characters can also begin a number, making `1rem-2vw` ambiguous. `*` and `/` are unambiguous, so `2*1rem` and `100%/3` parse fine. Most style guides still space every operator for consistency, and linters generally accept both forms.
- What does the browser do when the declaration is invalid?It discards that single declaration and keeps everything else — the rest of the rule, the rest of the stylesheet. There is no thrown error, so the element quietly keeps whatever value the cascade already gave it, usually the inherited size. The symptom is a fluid value that does not change at any viewport width; devtools shows the declaration struck through or missing.
- Is 1rem * 2vw a valid expression inside clamp()?No. In CSS math, multiplication requires at least one operand to be a plain number, so `2 * 1rem` is valid but `1rem * 2vw` is not — multiplying two lengths would produce an area, which no CSS property accepts. Division follows the mirror rule: the divisor must be a plain number, as in `100% / 3`.
saying these in an interview costs you the question
- Claiming calc() is required around arithmetic inside clamp()
- Thinking the browser reports an error for an invalid declaration
- Believing the whole rule or stylesheet is discarded
- Assuming mixing rem and vw is what makes it invalid
- Saying * and / also require surrounding whitespace