PostCSS plugin to transform :not() W3C CSS level 4 pseudo class to :not() CSS level 3 selectors
npx @tessl/cli install tessl/npm-postcss-selector-not@8.0.00
# PostCSS Selector Not
1
2
PostCSS Selector Not is a PostCSS plugin that transforms CSS level 4 `:not()` pseudo-class selectors with multiple arguments into CSS level 3 compatible selectors. It converts modern `:not(.a, .b)` syntax to `:not(.a):not(.b)` to ensure compatibility with older browsers while allowing developers to use the more concise modern syntax.
3
4
## Package Information
5
6
- **Package Name**: postcss-selector-not
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install postcss-selector-not --save-dev`
10
- **Node Version**: >=18
11
- **PostCSS Version**: ^8.4 (peer dependency)
12
13
## Core Imports
14
15
```typescript
16
import postcssSelectorNot from "postcss-selector-not";
17
// Named export also available
18
import type { pluginOptions } from "postcss-selector-not";
19
```
20
21
For CommonJS:
22
23
```javascript
24
const postcssSelectorNot = require("postcss-selector-not");
25
```
26
27
## Basic Usage
28
29
```typescript
30
import postcss from "postcss";
31
import postcssSelectorNot from "postcss-selector-not";
32
33
// Basic PostCSS usage
34
const result = await postcss([
35
postcssSelectorNot()
36
]).process(css, { from: undefined });
37
38
console.log(result.css);
39
```
40
41
Example transformation:
42
43
```css
44
/* Input CSS */
45
p:not(:first-child, .special) {
46
color: red;
47
}
48
49
/* Output CSS */
50
p:not(:first-child):not(.special) {
51
color: red;
52
}
53
```
54
55
## Architecture
56
57
PostCSS Selector Not follows the standard PostCSS plugin architecture:
58
59
- **Plugin Creator**: Factory function that returns a PostCSS plugin instance
60
- **Rule Processing**: Processes CSS rules containing `:not()` selectors
61
- **Selector Parsing**: Uses `postcss-selector-parser` for reliable CSS selector manipulation
62
- **Error Handling**: Provides warnings for invalid selectors without breaking the build
63
- **Transformation Logic**: Expands multi-argument `:not()` selectors into separate single-argument `:not()` functions
64
65
## Capabilities
66
67
### Plugin Creator Function
68
69
Creates a PostCSS plugin instance for transforming `:not()` selectors.
70
71
```typescript { .api }
72
/**
73
* Creates a PostCSS plugin for transforming CSS level 4 :not() selectors
74
* @param options - Plugin configuration options (currently none supported)
75
* @returns PostCSS plugin instance
76
*/
77
declare function postcssSelectorNot(options?: pluginOptions): Plugin;
78
79
/** Plugin options type - currently no options are supported */
80
type pluginOptions = Record<string, never>;
81
```
82
83
The plugin creator function returns a PostCSS plugin object with:
84
- `postcssPlugin`: String identifier "postcss-selector-not"
85
- `Rule`: Function that processes CSS rules containing `:not()` selectors
86
87
### Plugin Properties
88
89
```typescript { .api }
90
/** PostCSS plugin flag indicating this is a valid PostCSS plugin */
91
postcssSelectorNot.postcss: true;
92
```
93
94
### Transformation Behavior
95
96
The plugin specifically targets `:not()` pseudo-class selectors that contain multiple simple selectors separated by commas. It performs the following transformations:
97
98
- **Input**: `:not(.a, .b)` → **Output**: `:not(.a):not(.b)`
99
- **Input**: `:not(tag1, tag2, tag3)` → **Output**: `:not(tag1):not(tag2):not(tag3)`
100
- **Input**: `:not(:hover, :focus)` → **Output**: `:not(:hover):not(:focus)`
101
102
**Supported selectors**:
103
- Class selectors: `.class`
104
- Type selectors: `tag`
105
- ID selectors: `#id`
106
- Pseudo-class selectors: `:hover`, `:focus`, etc.
107
- Attribute selectors: `[attr="value"]`
108
109
**Limitations**:
110
- Only simple selectors are supported within `:not()`
111
- Complex selectors like `:not(.a > .b, .c ~ .d)` cannot be downgraded and will be left unchanged
112
- The plugin only processes selectors that contain `:not(` (case-insensitive)
113
114
### Error Handling
115
116
The plugin includes comprehensive error handling:
117
118
- **Selector Parsing Errors**: If a selector cannot be parsed by `postcss-selector-parser`, the plugin will issue a PostCSS warning with the selector string and error message
119
- **Invalid Selectors**: Malformed selectors are reported but don't break the build process
120
- **Graceful Degradation**: When transformation fails, the original selector is preserved
121
122
**Warning Format**:
123
```
124
Failed to parse selector : "invalid-selector" with message: "error details"
125
```
126
127
## Types
128
129
```typescript { .api }
130
/** Plugin options type - currently no configuration options are supported */
131
type pluginOptions = Record<string, never>;
132
133
/** PostCSS Plugin interface */
134
interface PostCSSPlugin {
135
postcssPlugin: string;
136
Rule(rule: PostCSSRule, helpers: { result: PostCSSResult }): void;
137
}
138
139
/** PostCSS Rule interface (from postcss library) */
140
interface PostCSSRule {
141
selector: string;
142
warn(result: PostCSSResult, message: string): void;
143
clone(overrides: { selector: string }): PostCSSRule;
144
replaceWith(newRule: PostCSSRule): void;
145
}
146
147
/** PostCSS Result interface (from postcss library) */
148
interface PostCSSResult {
149
// PostCSS processing result object
150
}
151
```
152
153
## Usage Examples
154
155
### Basic Webpack Configuration
156
157
```javascript
158
const postcssSelectorNot = require("postcss-selector-not");
159
160
module.exports = {
161
module: {
162
rules: [
163
{
164
test: /\.css$/,
165
use: [
166
"style-loader",
167
"css-loader",
168
{
169
loader: "postcss-loader",
170
options: {
171
postcssOptions: {
172
plugins: [
173
postcssSelectorNot()
174
]
175
}
176
}
177
}
178
]
179
}
180
]
181
}
182
};
183
```
184
185
### PostCSS Configuration File
186
187
```javascript
188
// postcss.config.js
189
module.exports = {
190
plugins: [
191
require("postcss-selector-not")()
192
]
193
};
194
```
195
196
### Complex Selector Examples
197
198
```css
199
/* Multiple pseudo-classes */
200
.button:not(:hover, :focus, :active) {
201
opacity: 0.8;
202
}
203
/* Becomes: */
204
.button:not(:hover):not(:focus):not(:active) {
205
opacity: 0.8;
206
}
207
208
/* Mixed selector types */
209
article:not(.featured, #special, [data-premium]) {
210
margin: 1rem;
211
}
212
/* Becomes: */
213
article:not(.featured):not(#special):not([data-premium]) {
214
margin: 1rem;
215
}
216
217
/* Nested :not() selectors */
218
.container :not(h1, h2) :not(.icon, .badge) {
219
font-size: 0.9rem;
220
}
221
/* Becomes: */
222
.container :not(h1):not(h2) :not(.icon):not(.badge) {
223
font-size: 0.9rem;
224
}
225
```