Spaces:
Sleeping
Sleeping
| # PostCSS Is Pseudo [<img src="https://postcss.github.io/postcss/logo.svg" alt="PostCSS" width="90" height="90" align="right">][postcss] | |
| [![NPM Version][npm-img]][npm-url] | |
| [![CSS Standard Status][css-img]][css-url] | |
| [<img alt="Build Status" src="https://github.com/csstools/postcss-plugins/workflows/test/badge.svg" height="20">][cli-url] | |
| [<img alt="Discord" src="https://shields.io/badge/Discord-5865F2?logo=discord&logoColor=white">][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](INSTALL.md#node) | [Webpack](INSTALL.md#webpack) | [Create React App](INSTALL.md#create-react-app) | [Gulp](INSTALL.md#gulp) | [Grunt](INSTALL.md#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](#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](https://polypane.app/css-specificity-calculator/#selector=%3Ais(%3Ahover%2C%20%3Afocus)%3Ais(.button%2C%20button)) | |
| ```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`._<br> | |
| _avoid these cases._<br> | |
| _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. | |
| [cli-url]: https://github.com/csstools/postcss-plugins/actions/workflows/test.yml?query=workflow/test | |
| [css-img]: https://cssdb.org/images/badges/is-pseudo-class.svg | |
| [css-url]: https://cssdb.org/#is-pseudo-class | |
| [discord]: https://discord.gg/bUadyRwkJS | |
| [npm-img]: https://img.shields.io/npm/v/@csstools/postcss-is-pseudo-class.svg | |
| [npm-url]: https://www.npmjs.com/package/@csstools/postcss-is-pseudo-class | |
| [CSS Selector]: https://www.w3.org/TR/selectors-4/#matches | |
| [PostCSS]: https://github.com/postcss/postcss | |
| [PostCSS Is Pseudo Class]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-is-pseudo-class | |