PostCSS Is Pseudo PostCSS

NPM Version CSS Standard Status Build Status Discord

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; }

Usage

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 | | --- | --- | --- | --- | --- |

Options

preserve

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; }

specificityMatchingName

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; } ```

onComplexSelector

Warn on complex selectors in :is pseudo class functions.

js postcss([ postcssIsPseudoClass({ onComplexSelector: 'warning' }) ]).process(YOUR_CSS /*, processOptions */);

onPseudoElement

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; } ```

⚠️ Known shortcomings

Specificity

: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 :

specificity: 0, 2, 0

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; } ```

Complex selectors

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.