# postcss-calc

> PostCSS plugin to reduce calc()

Latest version **11.1.1** (published 2026-09-07) · MIT license · 0 weekly downloads

## Install

```sh
npm install postcss-calc
pnpm add postcss-calc
yarn add postcss-calc
bun add postcss-calc
```

## Health

**Score 58/100 (C)** — status: active.

Positive: has types package; no vulnerabilities; recently updated; high maintenance score.

Warnings: low downloads; no esm support.

## Facts

| | |
|---|---|
| Version | 11.1.1 |
| Published | 2026-09-07 |
| First published | 2014-08-04 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | separate (@types/postcss-calc) |
| Module format | CommonJS |
| Dependencies | 0 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 222 |
| Author | Andy Jansson |
| Maintainers | beneb, moox, ludovicofischer, semigradsky, jonathantneal, andyjansson, evilebottnawi |
| Keywords | css, postcss, postcss-plugin, calculation, calc |

## Links

- npm: https://www.npmjs.com/package/postcss-calc
- Repository: https://github.com/postcss/postcss-calc
- npm.io page: https://npm.io/package/postcss-calc

## Alternatives

- [style-dictionary](https://npm.io/package/style-dictionary.md) — 2.0M weekly downloads
- [postcss-merge-idents](https://npm.io/package/postcss-merge-idents.md) — 1.7M weekly downloads
- [@fontsource/noto-sans](https://npm.io/package/@fontsource/noto-sans.md) — 93.0K weekly downloads
- [uglifycss](https://npm.io/package/uglifycss.md) — 71.6K weekly downloads
- [mat4-interpolate](https://npm.io/package/mat4-interpolate.md) — 23.3K weekly downloads

## Recent versions

- 11.1.1 (latest) — 2026-09-07
- 11.0.0-rc.3 (next) — 2026-08-14
- 11.1.0 — 2026-09-07
- 11.0.3 — 2026-09-01
- 11.0.2 — 2026-08-30
- 11.0.1 — 2026-08-26
- 11.0.0 — 2026-08-20
- 11.0.0-rc.2 — 2026-08-04
- 11.0.0-rc.1 — 2026-07-29
- 11.0.0-rc.0 — 2026-07-17
- 10.1.1 — 2025-01-31
- 10.1.0 — 2025-01-07
- 10.0.2 — 2024-08-16
- 10.0.1 — 2024-08-05
- 10.0.0 — 2024-04-26
- … 32 more at https://npm.io/package/postcss-calc/versions

## README

# PostCSS Calc [<img src="https://postcss.github.io/postcss/logo.svg" alt="PostCSS" width="90" height="90" align="right">][PostCSS]

[![NPM Version][npm-img]][npm-url]
[![Support Chat][git-img]][git-url]

[PostCSS Calc] lets you reduce `calc()` references whenever it's possible.
When multiple units are mixed together in the same expression, the `calc()`
statement is left as is, to fallback to the [W3C calc() implementation].

## Installation

```bash
npm install postcss-calc
```

## PostCSS usage

```js
// dependencies
var fs = require('fs');
var postcss = require('postcss');
var calc = require('postcss-calc');

// css to be processed
var css = fs.readFileSync('input.css', 'utf8');

// process css
var output = postcss().use(calc()).process(css).css;
```

Using this `input.css`:

```css
h1 {
  font-size: calc(16px * 2);
  height: calc(100px - 2em);
  width: calc(2 * var(--base-width));
  margin-bottom: calc(16px * 1.5);
}
```

you will get:

```css
h1 {
  font-size: 32px;
  height: calc(100px - 2em);
  width: calc(2 * var(--base-width));
  margin-bottom: 24px;
}
```

Checkout [tests] for more examples.

## Use the reducer without PostCSS

For a single CSS component-value string, import the dedicated reducer entry
point. It reduces `calc()` and the supported CSS math functions it finds while
leaving all other text untouched.

```js
import reduceCalc from 'postcss-calc/reduce';

reduceCalc('calc(1in + 10px)');
// => '1.10417in'

reduceCalc('min(50px, calc(2 * 40px))');
// => '50px'
```

It accepts `precision`, `unwrapSingleNegativeNumber`, `warnWhenCannotResolve`, `onParseError`,
and `onWarn`:

```js
const result = reduceCalc('calc(100% + var(--gap))', {
  precision: false,
  warnWhenCannotResolve: true,
  onWarn: console.warn,
  onParseError(error, input) {
    console.error(`Invalid calculation: ${input}`, error);
  },
});
```

Unlike the PostCSS plugin, the standalone reducer does not show warnings
by default; provide `onParseError` and/or `onWarn` if you want diagnostics.

### Standalone reducer options

#### `unwrapSingleNegativeNumber` (default: `false`)

Controls whether a finite negative result is serialized as a bare value or
wrapped in `calc()`. Keep the default when reducing declaration values; set it
to `true` when the surrounding CSS context requires a bare negative value, such
as a selector:

```js
reduceCalc('calc(5px - 10px)');
// => 'calc(-5px)'

reduceCalc('calc(5px - 10px)', { unwrapNegativeNumbers: true });
// => '-5px'
```

### PostCSS plugin options

These options apply when using the PostCSS plugin:

```js
postcss().use(calc({ precision: 10 }));
```

#### `precision` (default: `5`)

Allows you to define the precision for decimal numbers. Set it to `false` to
disable rounding.

```js
var out = postcss()
  .use(calc({ precision: 10 }))
  .process(css).css;
```

#### `warnWhenCannotResolve` (default: `false`)

Adds warnings when calc() are not reduced to a single value.

```js
var out = postcss()
  .use(calc({ warnWhenCannotResolve: true }))
  .process(css).css;
```

#### `mediaQueries` (default: `false`)

Allows calc() usage in media query parameters.

```js
var out = postcss()
  .use(calc({ mediaQueries: true }))
  .process(css).css;
```

Example:

```css
@media (min-width: calc(100px + 100px)) {
  div {
    width: 100px;
  }
}
```

With `mediaQueries: true`, this becomes:

```css
@media (min-width: 200px) {
  div {
    width: 100px;
  }
}
```

#### `selectors` (default: `false`)

Reduces `calc()` functions found in selectors. Selectors do not accept
`calc()` functions, so the plugin replaces them with their reduced values.
Finite negative results are serialized as bare values because a selector cannot
contain a `calc()` function; the plugin enables `unwrapSingleNegativeNumber` automatically
for selectors.

```js
var out = postcss()
  .use(calc({ selectors: true }))
  .process(css).css;
```

Example:

```css
div:nth-child(calc(1 + 2)) {
  width: 100px;
}
```

With `selectors: true`, this becomes `div:nth-child(3)`.

#### `onParseError`

Callback invoked when a `calc()` body fails to parse or simplify. Matches
[`@csstools/css-calc`][csstools-css-calc]'s shape:

```js
postcss().use(
  calc({
    onParseError: (err, input) => {
      throw err; // or log, route to a different channel, etc.
    },
  })
);
```

When omitted, errors are reported via PostCSS `result.warn()` so the
plugin never throws at the postcss level.

### Behavior differences from the legacy parser

The legacy [jison][jison]-generated parser was replaced by a hand-written
Pratt parser whose simplifier follows [CSS Values 4][css-values-4]. Most
inputs reduce to identical output; the differences are spec-aligned or
canonical-form decisions:

- **Strict whitespace (§10.1).** `calc(2px+3px)` is invalid CSS (binary
  `+` / `-` require surrounding whitespace) and is preserved with a
  warning instead of reduced.
- **Canonical operand order.** Commutative operands serialize
  numeric-first, matching [`@csstools/css-calc`][csstools-css-calc]:
  `calc(var(--foo) + 10px)` → `calc(10px + var(--foo))`.
- **Zero buckets are kept.** `calc(100px - (100px - 100%))` →
  `calc(0px + 100%)`, not `100%` — [WPT calc-serialization-002][wpt-calc-serialization]
  requires the zero term because it carries the length-percentage type.
- **Constant folding.** `calc(43 + pi)` now folds to `46.14159` (§10.7.1).
  Previously `pi` / `e` stayed symbolic.
- **Reciprocal conversion.** `calc(var(--x) / 2)` becomes
  `calc(var(--x) * 0.5)`. The two are mathematically equivalent;
  previously the division shape was kept.
- **Distributive multiplication.** `calc(0.5 * (100vw - 10px))` becomes
  `calc(50vw - 5px)`.
- **Unit case normalization.** `2PX` becomes `2px` (CSS units are case-
  insensitive; lowercase is conventional).
- **Calc unwrap (§10.6).** `calc(var(--foo))` becomes `var(--foo)` — a
  `calc()` containing a single value is replaced by that value.
- **Spec-style spaced operators.** `2px*var(--x)` is serialized as
  `2px * var(--x)`. The tokenizer is unaffected; only output spacing
  differs.
- **Division by zero / by a unit.** `calc(500px/0)` reduces to
  `calc(infinity * 1px)` (§10.13) instead of throwing. Use `onParseError`
  if you want validation behavior.

[css-values-4]: https://www.w3.org/TR/css-values-4/
[csstools-css-calc]: https://www.npmjs.com/package/@csstools/css-calc
[wpt-calc-serialization]: https://github.com/web-platform-tests/wpt/blob/master/css/css-values/calc-serialization-002.html
[jison]: https://github.com/zaach/jison

---

## Related PostCSS plugins

To replace the value of CSS custom properties at build time, try [PostCSS Custom Properties].

## Contributing

Work on a branch, install dev-dependencies, respect coding style & run tests
before submitting a bug fix or a feature.

```bash
git clone git@github.com:postcss/postcss-calc.git
git checkout -b patch-1
npm install
npm test
```

The normal test run uses a deterministic structural sample of the harvested
real-world corpus. Run the complete differential corpus before releases or
when changing parsing/simplification behavior:

```bash
pnpm test:corpus:full
```

Profile long arithmetic parser chains with `pnpm benchmark:arithmetic-chains`.

## [Changelog](CHANGELOG.md)

## [License](LICENSE)

[git-img]: https://img.shields.io/badge/support-chat-blue.svg
[git-url]: https://gitter.im/postcss/postcss
[npm-img]: https://img.shields.io/npm/v/postcss-calc.svg
[npm-url]: https://www.npmjs.com/package/postcss-calc
[PostCSS]: https://github.com/postcss
[PostCSS Calc]: https://github.com/postcss/postcss-calc
[PostCSS Custom Properties]: https://github.com/postcss/postcss-custom-properties
[tests]: test/index.js
[W3C calc() implementation]: https://www.w3.org/TR/css3-values/#calc-notation

---
_Source: https://npm.io/package/postcss-calc · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
