postcss-advanced-variables-plus
v1.4.3
Published
Use Sass-like variables, conditionals, and iterators in CSS — a modernised TypeScript fork of postcss-advanced-variables
Downloads
1,182
Readme
postcss-advanced-variables-plus
Use Sass-like variables, conditionals, and iterators in CSS.
Based on postcss-advanced-variables by Jonathan Neal and the csstools contributors. This fork adds TypeScript sources, a built-in pnpm/Vite-compatible resolver, and an aliases option.
Attribution
Original work by Jonathan Neal (@jonathantneal):
- Original repo: jonathantneal/postcss-advanced-variables
- Current upstream: csstools/postcss-advanced-variables
- License: CC0-1.0
Install
npm install postcss-advanced-variables-plusPostCSS is a peer dependency:
npm install postcssUsage
// postcss.config.js
import advancedVariables from "postcss-advanced-variables-plus";
export default {
plugins: [advancedVariables()],
};#{} interpolation in selectors and property names
PostCSS's standard CSS parser rejects #{...} in selectors, property names, and declaration values because { would be interpreted as opening a block. To use #{} in those positions, pair this plugin with a SCSS-aware syntax:
npm install postcss-scssimport postcssScss from "postcss-scss";
export default {
syntax: postcssScss,
plugins: [advancedVariables()],
};/* now valid with postcss-scss */
$layers: alpha, beta, gamma;
:root {
@each $layer in $layers {
--#{$layer}: 1; /* CSS custom property with interpolated name */
}
}
.nav {
$c: nav;
#{$c}__label { color: red; } /* BEM selector interpolation */
}#{} inside at-rule params works without postcss-scss because the surrounding () protect the inner { from being misread by the standard parser:
/* works without postcss-scss */
$bp: 600px;
@media (min-width: #{$bp}) {
}@each over lists and maps
Lists can expose the current value and optional numeric index:
@each $name, $index in (sm, md, lg) {
.size-$index {
content: "$name";
}
}
/* → .size-0 { content: "sm"; } ... */Maps use Sass-style comma syntax: the first variable receives the key, the second receives the value. Quoted keys are supported.
$colors: ("brand": #0a66ff, "accent": #f43f5e);
@each $name, $value in $colors {
.text-$name {
color: $value;
}
}
/* → .text-brand { color: #0a66ff; } ... */For backwards compatibility, the legacy space-separated map syntax is still supported with the original order: value first, key second.
@each $value $name in $colors {
.text-$name {
color: $value;
}
}With Vite aliases
// vite.config.js
import { defineConfig } from "vite";
const aliases = {
"@styles": "/src/styles",
"@tokens": "/src/tokens",
};
export default defineConfig({
resolve: { alias: aliases },
css: {
postcss: {
plugins: [advancedVariables({ aliases })],
},
},
});Options
| Option | Type | Default | Description |
| --------------- | ------------------------------------------ | ----------------- | --------------------------------------------------------------- |
| variables | VariableMap \| (name, node) => value | {} | Additional variables available to all files |
| unresolved | "throw" \| "warn" \| "ignore" | "throw" | Behaviour when a variable reference cannot be resolved |
| disable | string | — | Space-separated list of at-rules to disable (e.g. "@if @for") |
| importPaths | string[] | [] | Additional directories to search when resolving @import |
| importResolve | (id, cwd) => Promise<{ file, contents }> | built-in resolver | Override the file resolver entirely |
| importFilter | ((id, media) => boolean) \| RegExp | — | Predicate to skip specific @import paths |
| importRoot | string | process.cwd() | Root directory for resolving bare imports |
| aliases | Record<string, string> | {} | Path aliases forwarded to the built-in resolver |
aliases in detail
Aliases are resolved using longest-prefix matching, the same strategy Vite uses. An exact match (e.g. @tokens with no trailing slash) is resolved to the target path as-is; a prefix match (e.g. @styles/button.css) replaces the alias segment and appends the rest.
/* with aliases: { '@styles': '/src/styles' } */
@import "@styles/button.css";
/* resolves to /src/styles/button.css */ImportResolverOptions (advanced)
When you need full control over specifier resolution without replacing the entire importResolve function, call createImportResolver directly:
import advancedVariables, { createImportResolver } from "postcss-advanced-variables-plus";
const resolve = createImportResolver({
aliases: { "@styles": "/src/styles" },
// Supply Vite's resolver instead of import.meta.resolve:
resolveId: (id, base) => viteDevServer.moduleGraph.resolveUrl(id),
});
advancedVariables({ importResolve: resolve });| Option | Type | Default | Description |
| ----------- | -------------------------------------- | --------------------- | ------------------------------ |
| aliases | Record<string, string> | {} | Path aliases |
| resolveId | (id: string, base: string) => string | import.meta.resolve | Specifier-to-file-URL resolver |
Differences from the original
| | postcss-advanced-variables | postcss-advanced-variables-plus |
| ---------------------------- | ------------------------------- | ------------------------------------ |
| Source language | JavaScript | TypeScript (strict) |
| Resolver | @csstools/sass-import-resolve | Built-in; uses import.meta.resolve |
| pnpm / exports map support | No | Yes |
| aliases option | No | Yes |
| Module format | CJS + ESM | ESM only |
| Node requirement | ≥ 12 | ≥ 18 |
Migration from postcss-advanced-variables
This package is a drop-in replacement. All existing options work identically.
- Uninstall the original:
npm uninstall postcss-advanced-variables npm install postcss-advanced-variables-plus - Update imports:
// before import advancedVariables from "postcss-advanced-variables"; // after import advancedVariables from "postcss-advanced-variables-plus"; - If you were passing a custom
importResolve, it continues to work unchanged. - If you relied on
@csstools/sass-import-resolvebehaviour for bare@importpaths (e.g.@import "bootstrap") you may need to add the relevant directory toimportPaths, or configurealiases.
License
CC0-1.0. See LICENSE.md.
Original work CC0-1.0 by Jonathan Neal and csstools contributors.
