What calc() does
calc() does arithmetic inside a CSS value, and it can mix units that only get a size at layout time. The classic case is "the full width minus a fixed sidebar":
100% is only known once the page is laid out, and 180px is fixed, so no single unit could express this. calc() works it out: in an 800px wide preview the row is 784px and the main column gets 604px, and the line under the layout prints the real numbers. Today flexbox or grid would do this layout without math, but the same subtraction still comes up everywhere: a height minus a header, a width minus a gap.
The syntax rules
width: calc(100% - 2rem); /* + and - need spaces on both sides */
width: calc(100% / 3); /* divide by a plain number */
margin: calc(var(--space) * 2); /* multiply by a plain number */
height: calc(100vh - (64px + 1rem)); /* parentheses group */
| Rule | Valid | Invalid |
|---|---|---|
Spaces around + and - | calc(100% - 20px) | calc(100%-20px) |
*: at least one side is a plain number | calc(2 * 1rem) | calc(2px * 3px) |
/: divide a length by a plain number | calc(100% / 3) | width: calc(300px / 3px) (not a length) |
| Units must be compatible | calc(1rem + 10px) | calc(1rem + 2s) |
The space rule exists because 100% -20px would read as two separate values, the second one a negative number. When a calc() is invalid, the whole declaration is thrown away and the element keeps whatever value it had from earlier rules.
Try an expression
Type any expression for the box's width. The browser reports whether it is valid, and the width it resolved to:
Try 100%-200px (invalid, no spaces), 100% / 3, 50% + 4rem, 2 * 120px, 200px * 2px (invalid) and (100% - 40px) / 2.
calc() with CSS variables
Variables and calc() go together: store a base value once and derive the rest from it. A unitless variable becomes a length when you multiply it by one unit:
Change --space to 12px or --cols to 4 and every derived value follows. The CSS variables page covers declaring and scoping them.
Common uses
| Need | calc() |
|---|---|
| Fill the space next to a fixed element | width: calc(100% - 240px) |
| Section below a fixed header | min-height: calc(100vh - 64px) |
| Half the width minus half a gap | width: calc(50% - 8px) |
| Center an absolutely positioned 100px box | left: calc(50% - 50px) |
| Font size that grows a little with the screen | font-size: calc(1rem + 0.5vw) |
| Turn a number variable into a length | calc(var(--n) * 1px) |
| Negative of a variable | calc(var(--space) * -1) |
For a value that must stay between limits, use clamp(), which accepts the same math in its arguments without writing calc().
Where calc() works
Anywhere a length, percentage, number, angle or time is allowed: width, margin, padding, top, font-size, line-height, grid track sizes, transition-delay, and angles inside transform. It can be nested, and a nested calc() is the same as plain parentheses.
Angles are a good example. Each tick below has its own --i (0 to 11), and one rule turns it into an angle with calc(var(--i) * 30deg):
Tick 3 gets rotate(90deg), which Chrome reports as the matrix matrix(0, 1, -1, 0, 0, 0): a quarter turn. left: calc(50% - 2px) centers each tick by subtracting half of its own 4px width.
Common mistakes
- No spaces around
-or+.calc(100%-20px)is invalid and ignored. - Multiplying two lengths.
calc(10px * 2px)has no meaning in CSS. One side of*must be a plain number. - Using calc() for a percentage height without a parent height.
calc(100% - 20px)forheightneeds a parent with a set height, likeheight: 100%does. - Using calc() where flexbox or grid would do.
width: calc(33.333% - 10px)for columns is fragile;display: grid; grid-template-columns: repeat(3, 1fr); gap: 15pxneeds no math. - Expecting an error message. The browser does not warn about an invalid calc(). Check the element in the developer tools: an invalid declaration is shown crossed out.
Frequently Asked Questions
What does calc() do in CSS?
It computes a value from an expression with +, -, * and /, and it can mix units the browser only knows at layout time. width: calc(100% - 200px) is the full width of the parent minus 200px, whatever the parent's width is.
Why is my calc() not working?
The most common cause is missing spaces: + and - must have whitespace on both sides, so calc(100%-20px) is invalid. Other causes are multiplying two lengths (10px * 2px) or dividing by a length, which does not give a length. An invalid calc() makes the whole declaration invalid, so the browser ignores it.
Can I use CSS variables in calc()?
Yes. calc(var(--gap) * 2) doubles a variable, and calc(var(--columns) * 1px) turns a unitless number into pixels. The variable's value is substituted first and then the math is done.
Do I need spaces around * and / in calc()?
No. Only + and - require spaces, because without them -20px would be read as a negative number. Spaces around * and / are optional, but writing them everywhere is the easiest rule to remember.
What is the difference between calc() and clamp()?
calc() computes one value from an expression. clamp(MIN, VAL, MAX) keeps a value between two limits. They combine: each argument of clamp() can already contain calc-style math, such as clamp(1rem, 1rem + 2vw, 3rem).