PostCSS Is Pseudo Class lets you use the :is
pseudo class function, following the
CSS Selector specification.
pcss
:is(input, button):is(:hover, :focus) {
order: 1;
}
Becomes :
pcss
input:hover {
order: 1;
}
input:focus {
order: 1;
}
button:hover {
order: 1;
}
button:focus {
order: 1;
}
Add PostCSS Is Pseudo Class to your project:
bash
npm install @csstools/postcss-is-pseudo-class --save-dev
Use PostCSS Is Pseudo Class as a PostCSS plugin:
```js import postcss from 'postcss'; import postcssIsPseudoClass from '@csstools/postcss-is-pseudo-class';
postcss([ postcssIsPseudoClass(/ pluginOptions /) ]).process(YOUR_CSS /, processOptions /); ```
PostCSS Is Pseudo Class runs in all Node environments, with special instructions for:
| Node | Webpack | Create React App | Gulp | Grunt | | --- | --- | --- | --- | --- |
The preserve
option determines whether the original notation
is preserved. By default, it is not preserved.
js
postcss([
postcssIsPseudoClass({ preserve: true })
]).process(YOUR_CSS /*, processOptions */);
pcss
:is(input, button):is(:hover, :focus) {
order: 1;
}
Becomes :
pcss
input:hover {
order: 1;
}
input:focus {
order: 1;
}
button:hover {
order: 1;
}
button:focus {
order: 1;
}
:is(input, button):is(:hover, :focus) {
order: 1;
}
The specificityMatchingName
option allows you to change to selector used to adjust specificity.
The default value is does-not-exist
.
If this is an actual class, id or tag name in your code, you will need to set a different option here.
See how :not
is used to modify specificity.
js
postcss([
postcssIsPseudoClass({ specificityMatchingName: 'something-random' })
]).process(YOUR_CSS /*, processOptions */);
pcss
:is(.button, button):hover {
order: 7;
}
Becomes :
```pcss .button:hover { order: 7; }
button:not(.something-random):hover { order: 7; } ```
Warn on complex selectors in :is
pseudo class functions.
js
postcss([
postcssIsPseudoClass({ onComplexSelector: 'warning' })
]).process(YOUR_CSS /*, processOptions */);
Warn when pseudo elements are used in :is
pseudo class functions.
⚠️ Pseudo elements are always invalid and will be transformed to ::-csstools-invalid-<pseudo-name>
.
js
postcss([
postcssIsPseudoClass({ onPseudoElement: 'warning' })
]).process(YOUR_CSS /*, processOptions */);
```css :is(::after):hover { order: 1.0; }
/ becomes /
::-csstools-invalid-after:hover { order: 1.0; } ```
:is
takes the specificity of the most specific list item.
We can increase specificity with :not
selectors, but we can't decrease it.
Converted selectors are ensured to have the same specificity as :is
for the most important bit.
Less important bits can have higher specificity that :is
.
Before :
pcss
:is(:hover, :focus):is(.button, button) {
order: 7;
}
After :
```pcss / specificity: [0, 2, 0] / .button:hover { order: 7; }
/ specificity: [0, 2, 1] / / last bit is higher than it should be, but middle bit matches / button:not(.does-not-exist):hover { order: 7; }
/ specificity: [0, 2, 0] / .button:focus { order: 7; }
/ specificity: [0, 2, 1] / / last bit is higher than it should be, but middle bit matches / button:not(.does-not-exist):focus { order: 7; } ```
Before :
pcss
:is(.alpha > .beta) ~ :is(:focus > .beta) {
order: 2;
}
After :
pcss
.alpha > .beta ~ :focus > .beta {
order: 2;
}
this is a different selector than expected as .beta ~ :focus
matches .beta
followed by :focus
.
avoid these cases.
writing the selector without :is()
is advised here
pcss
/* without is */
.alpha:focus > .beta ~ .beta {
order: 2;
}
If you have a specific pattern you can open an issue to discuss it. We can detect and transform some cases but can't generalize them into a single solution that tackles all of them.