Mix any units, solve layout math, and skip JavaScript entirely.
Pick values and units, choose an operator. The expression builds in real time and the result
bar shows the computed width. This is the power of calc() — mixing units the browser
can't add any other way.
100% - 32px in plain CSS — the browser
doesn't know what 100% minus 32 pixels equals until layout time. calc() defers the
calculation to the browser, which solves it at render time when both values are known.
The whole point of calc() is mixing units the browser can't combine any other way.
But not all combinations are valid. Here's the complete rulebook.
| Operation | Rule | Example | Valid? |
|---|---|---|---|
| Addition (+) | Both sides need compatible units | calc(100% + 20px) |
Yes |
| Subtraction (−) | Both sides need compatible units | calc(100vh - 60px) |
Yes |
| Multiplication (×) | One side must be unitless | calc(var(--base) * 2) |
Yes |
| Multiplication (×) | Both sides with units | calc(20px * 5px) |
No — gives px² |
| Division (÷) | Right side must be unitless | calc(100% / 3) |
Yes |
| Division (÷) | Dividing by zero | calc(100px / 0) |
No — invalid |
| Nested calc() | calc() inside calc() | calc(calc(100% - 20px) / 2) |
Yes — but use () instead |
calc(100% -32px) is invalid.
Always write calc(100% - 32px) with spaces around + and -.
The * and / operators don't strictly require spaces, but use them for readability.
Four patterns you'll reach for every project, plus the three most common reasons
calc() silently fails.
grid-template-columns: 200px calc(100% - 208px) — sidebar is fixed,
main area fills the rest minus the gap.
margin-inline: calc(50% - 50vw) — breaks an element out of a constrained
container to span the full viewport width.
width: calc(100% / 3 - gap) — three equal columns that always sum to
exactly 100% regardless of container size.
top: calc(var(--header-height) + 16px) — sticky sidebar clears the sticky
header automatically when the variable changes.
This is the #1 reason calc() silently produces no result. The + and - operators must have whitespace on both sides. Without it, the browser misreads the expression — a - without spaces looks like a negative number, not subtraction.
CSS custom properties store values as-is. If a variable holds a unitless number like --size: 16, you cannot add a unit to it inside calc() by writing calc(var(--size)px) — that's not valid syntax. The unit must be in the variable itself, or multiply by 1px.
calc() works in any property that accepts a length, percentage, angle, time, or frequency value. It does NOT work in media query conditions, animation steps(), or selector arguments — those require static values.
+ and -? (2) CSS variables have units included? (3) Not inside a @media condition? (4) Division right side is unitless?