or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/npm-postcss-discard-overridden

PostCSS plugin to discard overridden @keyframes or @counter-style rules.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/postcss-discard-overridden@7.0.x

To install, run

npx @tessl/cli install tessl/npm-postcss-discard-overridden@7.0.0

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

```