CSS Calc and Math Functions
Custom properties gave you named values. Math functions let those values (and plain lengths) compute at render time: subtract a sidebar from 100%, cap a column with min(), or grow type smoothly with clamp() — no Sass build step required.
calc() — arithmetic in property values
Wrap an expression in calc(...). The browser evaluates it when computing the property. Plus and minus need spaces around the operator; * and / can be tighter but stay readable:
:root {
--sidebar-w: 16rem;
--gap: 1rem;
}
.layout {
display: flex;
gap: var(--gap);
}
.sidebar {
flex: 0 0 var(--sidebar-w);
}
.main {
flex: 1 1 auto;
min-width: 0;
/* readable fallback when flex alone is not enough */
max-width: calc(100% - var(--sidebar-w) - var(--gap));
}
Here calc() expresses “remaining width” explicitly — useful in grids, absolute positioning, or when a parent is not flex. You can mix %, rem, px, vw, and var(--tokens) as long as the result is valid for that property.
Spaces and unit rules (calc gotchas)
Invalid: calc(100%-2rem) — the parser needs space before -. Valid: calc(100% - 2rem). Multiplication requires at least one number factor: calc(var(--space) * 2) works; calc(2rem * 3rem) does not.
.card {
--space: 0.75rem;
padding: var(--space) calc(var(--space) * 2);
margin-block: calc(var(--space) / 2);
}
calc() runs at computed-value time, so it sees the resolved var(--space). That pairs naturally with the variables lesson — tokens supply numbers, math functions transform them into layout.
min() and max() — pick an extreme
Both accept a comma-separated list of lengths. min() returns the smallest; max() the largest. Handy for responsive caps without a media query for every breakpoint:
.hero-inner {
width: min(100% - 2rem, 72rem);
margin-inline: auto;
}
.feature-grid {
grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
}
min(100% - 2rem, 72rem) means “full width minus gutters, but never wider than 72rem”. minmax(...) inside grid is a common pairing — the inner min() avoids overflow on narrow screens.
clamp() — bounded fluid values
clamp(MIN, PREFERRED, MAX) is shorthand for “at least MIN, at most MAX, otherwise PREFERRED”. Order matters: minimum first, maximum last. Perfect for fluid type and fluid spacing:
:root {
--text-base: clamp(1rem, 0.95rem + 0.35vw, 1.125rem);
--heading-lg: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
}
body {
font-size: var(--text-base);
}
h1 {
font-size: var(--heading-lg);
line-height: 1.2;
}
The middle term often mixes rem + vw so size grows with viewport but stops at the caps. You can nest clamp() inside var() on :root — one token update retunes the whole scale.
Which function when?
📊 Math functions at a glance
| Function | Think of it as | Typical use |
|---|---|---|
| calc() | Spreadsheet cell for one property | Subtract gutters, add offsets, double a token with * 2 |
| min() | “No larger than…” among choices | Cap width, pick narrower of % and px |
| max() | “At least this big…” | Floor a size, ensure touch target minimum |
| clamp() | min + preferred + max in one | Fluid font-size, fluid section padding with hard limits |
You can combine them: width: min(100%, calc(var(--max-w) + 2rem)); — keep expressions readable; split into tokens on :root when a formula repeats.
Sticky footer helper with max()
When content is short, the footer should still sit at the bottom; when content grows, the block expands:
:root {
--header-h: 4rem;
}
.page {
min-height: max(100vh, calc(100vh - var(--header-h) + 100%));
}
/* simpler pattern most teams use */
.page-simple {
min-height: calc(100vh - var(--header-h));
display: flex;
flex-direction: column;
}
Prefer the simple pattern when it matches your layout; the lesson shows that math functions express relationships declaratively in CSS — not only in JavaScript or preprocessors.
Try it yourself
- Build a two-column row: fixed
--sidebar-w,calc(100% - var(--sidebar-w) - gap)on the main pane. - Replace a rigid
font-size: 24pxwithclamp(1.25rem, 1rem + 1.5vw, 2rem)and resize the viewport. - Use
min(100%, 40rem)on a article wrapper; compare with plainwidth: 100%. - Move a repeated formula to
:rootas--content-w: min(100% - 2rem, 70rem);and reuse it in three selectors. - Fix
calc(100%-1rem)by adding spaces; confirm DevTools no longer strikes the declaration.
Common mistakes
calc(100%-2rem)without spaces around-— rule failsclamp(2rem, 1rem + 1vw, 1rem)with min greater than max — confusing or ignored behavior- Using
max()when you meant a ceiling (oftenmin()instead) - Putting
calc(...)in a property name — only values, likevar() - Expecting
calc()to divide two lengths likecalc(10rem / 2rem)— division needs a number divisor
Summary
calc()adds, subtracts, multiplies, and divides in values — mind spaces around+/-min()/max()choose among comma-separated lengths for caps and floorsclamp(min, preferred, max)drives fluid typography and spacing with bounds- Pair math with
var(--tokens)for maintainable responsive layout - Next in Modern Toolkit: native CSS nesting for clearer selector structure
🧠 Test Your Knowledge
Test Your Knowledge
Challenge yourself with this interactive quiz and see how well you understand the topic
📝 Instructions
- Read each question carefully
- Select the best answer for each question
- You can retake the quiz as many times as you want
- Your progress will be shown at the top