What is postcss-prefix-selector?
The postcss-prefix-selector npm package is a PostCSS plugin that allows you to add a prefix to all CSS selectors. This can be useful for scoping styles to a specific part of a page, avoiding conflicts with other styles, or applying styles conditionally.
What are postcss-prefix-selector's main functionalities?
Prefixing all selectors
This feature allows you to add a prefix to all CSS selectors. In this example, the selector '.foo' is prefixed with '.my-prefix', resulting in '.my-prefix .foo'.
const postcss = require('postcss');
const prefixer = require('postcss-prefix-selector');
const css = '.foo { color: red; }';
postcss([prefixer({ prefix: '.my-prefix' })])
.process(css)
.then(result => {
console.log(result.css);
});
// Output: .my-prefix .foo { color: red; }
Excluding specific selectors
This feature allows you to exclude specific selectors from being prefixed. In this example, the selector '.bar' is excluded from being prefixed, so only '.foo' is prefixed.
const postcss = require('postcss');
const prefixer = require('postcss-prefix-selector');
const css = '.foo { color: red; } .bar { color: blue; }';
postcss([prefixer({ prefix: '.my-prefix', exclude: ['.bar'] })])
.process(css)
.then(result => {
console.log(result.css);
});
// Output: .my-prefix .foo { color: red; } .bar { color: blue; }
Transforming the prefix
This feature allows you to transform the prefix in a custom way. In this example, the prefix is transformed to include '--' between the prefix and the selector.
const postcss = require('postcss');
const prefixer = require('postcss-prefix-selector');
const css = '.foo { color: red; }';
postcss([prefixer({ prefix: '.my-prefix', transform: (prefix, selector, prefixedSelector) => `${prefix}--${selector}` })])
.process(css)
.then(result => {
console.log(result.css);
});
// Output: .my-prefix--.foo { color: red; }
Other packages similar to postcss-prefix-selector
postcss-nested
The postcss-nested package allows you to nest your CSS selectors in a way that follows the same visual hierarchy of your HTML. While it doesn't add prefixes, it helps in organizing and scoping styles in a nested manner, which can be an alternative approach to managing CSS scope.
postcss-namespace
The postcss-namespace package is another PostCSS plugin that helps in scoping CSS by adding a namespace to your selectors. It is similar to postcss-prefix-selector but focuses on adding a namespace rather than a simple prefix.
postcss-scopify
The postcss-scopify package allows you to scope your CSS by adding a specific scope to your selectors. It is similar to postcss-prefix-selector but offers more flexibility in defining the scope.
postcss-prefix-selector
Prefix every CSS selector with a custom namespace .a => .prefix .a
Table of Contents
Install
$ npm install postcss-prefix-selector
Usage with PostCSS
A prefix is added before most selectors. Below is an example of how CSS will be transformed by adding a prefix called .namespace
.
const prefixer = require('postcss-prefix-selector')
const css = fs.readFileSync("input.css", "utf8")
const out = postcss().use(prefixer({
prefix: '.namespace',
exclude: ['.c'],
})).process(css).css
.a, .b {
color: aqua;
}
.c {
color: coral;
}
.namespace .a, .namespace .b {
color: aqua;
}
.c {
color: coral;
}
Please note that global selectors (html
, body
, :root
) cannot be prefixed so instead they will be replaced with the prefix. This behaviour can be disabled with the skipGlobalSelectors
option.
:root { --bs-blue:#0d6efd; }
html { padding: 0; }
body { margin: 0; }
.namespace { --bs-blue:#0d6efd; }
.namespace { padding: 0; }
.namespace { margin: 0; }
It's also possible to customize the way prefixing is done by defining a transform function:
const out = postcss().use(prefixer({
prefix: '.namespace',
transform: function (prefix, selector, prefixedSelector, filePath, rule) {
if (selector === 'body') {
return 'body' + prefix;
} else {
return prefixedSelector;
}
}
})).process(css).css
body {
background: red;
}
body.namespace {
background: red;
}
Usage with webpack
Use it like you'd use any other PostCSS plugin. If you also have autoprefixer
in your webpack config then make sure that postcss-prefix-selector
is called first. This is needed to avoid running the prefixer twice on both standard selectors and vendor specific ones (ex: @keyframes
and @webkit-keyframes
).
module: {
rules: [{
test: /\.css$/,
use: [
require.resolve('style-loader'),
require.resolve('css-loader'),
{
loader: require.resolve('postcss-loader'),
options: {
postcssOptions: {
plugins: {
"postcss-prefix-selector": {
prefix: '.my-prefix',
transform(prefix, selector, prefixedSelector, filePath, rule) {
if (selector.match(/^(html|body)/)) {
return selector.replace(/^([^\s]*)/, `$1 ${prefix}`);
}
if (filePath.match(/node_modules/)) {
return selector;
}
const annotation = rule.prev();
if (annotation?.type === 'comment' && annotation.text.trim() === 'no-prefix') {
return selector;
}
return prefixedSelector;
},
},
autoprefixer: {
browsers: ['last 4 versions']
}
}
}
}
}
]
}]
}
Usage with Vite
Following the same way of Webpack but for Vite:
import prefixer from 'postcss-prefix-selector';
import autoprefixer from 'autoprefixer';
...
export default defineConfig({
...
css: {
postcss: {
plugins: [
prefixer({
prefix: '.my-prefix',
transform(prefix, selector, prefixedSelector, filePath, rule) {
if (selector.match(/^(html|body)/)) {
return selector.replace(/^([^\s]*)/, `$1 ${prefix}`);
}
if (filePath.match(/node_modules/)) {
return selector;
}
const annotation = rule.prev();
if (annotation?.type === 'comment' && annotation.text.trim() === 'no-prefix') {
return selector;
}
return prefixedSelector;
},
}),
autoprefixer({})
],
}
},
...
});
Options
Name | Type | Description |
---|
prefix | string | This string is added before every CSS selector |
exclude | string[] or RegExp[] | It's possible to avoid prefixing some selectors by passing an array of selectors |
transform | Function | In cases where you may want to use the prefix differently for different selectors, it is possible to pass in a custom transform method |
ignoreFiles | string[] or RegExp[] | List of ignored files for processing |
includeFiles | string[] or RegExp[] | List of included files for processing |
skipGlobalSelectors | boolean | When enabled, global selectors (html , body , root ) won't be modified by the prefixer. Default: false . |
Maintainer
This project was originally created by @jongleberry and is being maintained by @RadValentin. If you have any questions, feel free to ping the latter.
Contribute
Please contribute! If you have any questions or bugs, open an issue. Or, open a pull request with a fix.
This project uses Mocha. If you submit a PR, please add appropriate tests and make sure that everything is green for your branch.
License
MIT © 2015-2024 Jonathan Ong.