0
# PostCSS Discard Overridden
1
2
PostCSS Discard Overridden is a PostCSS plugin that optimizes CSS by automatically removing overridden `@keyframes` and `@counter-style` rules. It intelligently identifies and removes duplicate declarations that are later overridden by identical rules with the same identifier, keeping only the last (and therefore effective) declaration.
3
4
The plugin handles complex scenarios including nested `@media` and `@supports` rules where `@keyframes` and `@counter-style` rules only override global rules in some browsers, ensuring safe AST transformations.
5
6
## Package Information
7
8
- **Package Name**: postcss-discard-overridden
9
- **Package Type**: npm
10
- **Language**: JavaScript
11
- **Installation**: `npm install postcss-discard-overridden`
12
13
## Core Imports
14
15
```javascript
16
const postcssDiscardOverridden = require('postcss-discard-overridden');
17
```
18
19
For ES modules:
20
21
```javascript
22
import postcssDiscardOverridden from 'postcss-discard-overridden';
23
```
24
25
## Basic Usage
26
27
```javascript
28
const postcss = require('postcss');
29
const discardOverridden = require('postcss-discard-overridden');
30
31
// Process CSS
32
const result = await postcss([discardOverridden()])
33
.process(css, { from: 'input.css', to: 'output.css' });
34
35
console.log(result.css);
36
```
37
38
Example transformation:
39
40
**Input CSS:**
41
```css
42
@keyframes fade-in {
43
0% { opacity: 0; }
44
100% { opacity: 0.8; }
45
}
46
47
@keyframes fade-in {
48
0% { opacity: 0; }
49
100% { opacity: 1; }
50
}
51
```
52
53
**Output CSS:**
54
```css
55
@keyframes fade-in {
56
0% { opacity: 0; }
57
100% { opacity: 1; }
58
}
59
```
60
61
## Capabilities
62
63
### Plugin Creator Function
64
65
The main export is a function that creates a PostCSS plugin instance.
66
67
```javascript { .api }
68
/**
69
* Creates a PostCSS plugin that removes overridden @keyframes and @counter-style rules
70
* @returns {import('postcss').Plugin} PostCSS plugin instance
71
*/
72
function postcssDiscardOverridden(): import('postcss').Plugin;
73
```
74
75
The plugin creator function takes no options and returns a PostCSS plugin with the following properties:
76
77
```javascript { .api }
78
interface PostCSSPlugin {
79
/** Plugin identifier for PostCSS */
80
postcssPlugin: 'postcss-discard-overridden';
81
/** Plugin preparation function */
82
prepare(): {
83
/** Function called once at the end of processing */
84
OnceExit(css: import('postcss').Root): void;
85
};
86
}
87
```
88
89
**Usage Example:**
90
91
```javascript
92
const postcss = require('postcss');
93
const discardOverridden = require('postcss-discard-overridden');
94
95
// Use with other PostCSS plugins
96
const processor = postcss([
97
require('autoprefixer'),
98
discardOverridden(),
99
require('cssnano')
100
]);
101
102
const result = await processor.process(css, { from: 'input.css' });
103
```
104
105
### PostCSS Compatibility
106
107
The plugin includes PostCSS compatibility markers:
108
109
```javascript { .api }
110
/** PostCSS compatibility flag */
111
postcssDiscardOverridden.postcss = true;
112
```
113
114
This ensures the plugin is compatible with PostCSS's plugin system and can be used in plugin arrays.
115
116
## Processing Logic
117
118
The plugin operates by:
119
120
1. **Scanning**: Walking through all at-rules in the CSS AST
121
2. **Identification**: Identifying overridable rules (`@keyframes`, `@counter-style`)
122
3. **Scope Analysis**: Building scope chains for rules nested within `@media`, `@supports`, etc.
123
4. **Deduplication**: Keeping only the last occurrence of each rule within its scope
124
5. **Removal**: Removing all earlier duplicate rules
125
126
### Supported At-Rules
127
128
The plugin processes these at-rule types:
129
130
- `@keyframes` (including vendor-prefixed variants like `@-webkit-keyframes`)
131
- `@counter-style` (including vendor-prefixed variants)
132
133
### Scope Handling
134
135
The plugin respects CSS cascade rules and scoping:
136
137
- **Global Scope**: Rules at the root level override each other completely
138
- **Media Queries**: Rules within `@media` blocks only override in matching conditions
139
- **Support Queries**: Rules within `@supports` blocks only override when features are supported
140
- **Nested Scopes**: Complex nesting scenarios are handled correctly
141
142
**Example with scoping:**
143
144
```css
145
/* Input */
146
@keyframes fade { /* ... */ }
147
@media (max-width: 500px) {
148
@keyframes fade { /* ... */ } /* Only overrides in narrow viewports */
149
}
150
@keyframes fade { /* ... */ } /* Overrides global fade */
151
152
/* Output - media query version is preserved */
153
@media (max-width: 500px) {
154
@keyframes fade { /* ... */ }
155
}
156
@keyframes fade { /* ... */ }
157
```
158
159
## Integration Patterns
160
161
### With Build Tools
162
163
```javascript
164
// webpack.config.js
165
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
166
167
module.exports = {
168
module: {
169
rules: [
170
{
171
test: /\.css$/,
172
use: [
173
MiniCssExtractPlugin.loader,
174
'css-loader',
175
{
176
loader: 'postcss-loader',
177
options: {
178
postcssOptions: {
179
plugins: [
180
require('postcss-discard-overridden')(),
181
require('autoprefixer'),
182
]
183
}
184
}
185
}
186
]
187
}
188
]
189
}
190
};
191
```
192
193
### With PostCSS CLI
194
195
```javascript
196
// postcss.config.js
197
module.exports = {
198
plugins: [
199
require('postcss-discard-overridden'),
200
require('autoprefixer'),
201
require('cssnano')
202
]
203
}
204
```
205
206
### Programmatic Usage
207
208
```javascript
209
const fs = require('fs');
210
const postcss = require('postcss');
211
const discardOverridden = require('postcss-discard-overridden');
212
213
async function processCSS(inputFile, outputFile) {
214
const css = fs.readFileSync(inputFile, 'utf8');
215
216
const result = await postcss([discardOverridden()])
217
.process(css, {
218
from: inputFile,
219
to: outputFile
220
});
221
222
fs.writeFileSync(outputFile, result.css);
223
224
if (result.map) {
225
fs.writeFileSync(outputFile + '.map', result.map.toString());
226
}
227
}
228
```
229
230
## Error Handling
231
232
The plugin operates on the PostCSS AST and does not throw errors under normal circumstances. It gracefully handles:
233
234
- Empty CSS files
235
- Files without `@keyframes` or `@counter-style` rules
236
- Malformed at-rules (passes them through unchanged)
237
- Complex nesting scenarios
238
239
PostCSS-level errors (syntax errors, etc.) are handled by the PostCSS parser before this plugin runs.
240
241
## Type Definitions
242
243
TypeScript definitions are available:
244
245
```typescript { .api }
246
declare function postcssDiscardOverridden(): import("postcss").Plugin;
247
declare namespace postcssDiscardOverridden {
248
let postcss: true;
249
}
250
251
export = postcssDiscardOverridden;
252
```