UNPKG

postcss-calc

Version:
222 lines (169 loc) 5.88 kB
# 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 ``` ## 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. ### Options #### `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`) Allows calc() usage as part of 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 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 ``` ## [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