or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

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

index.mddocs/

PostCSS Discard Overridden

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.

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.

Package Information

  • Package Name: postcss-discard-overridden
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install postcss-discard-overridden

Core Imports

const postcssDiscardOverridden = require('postcss-discard-overridden');

For ES modules:

import postcssDiscardOverridden from 'postcss-discard-overridden';

Basic Usage

const postcss = require('postcss');
const discardOverridden = require('postcss-discard-overridden');

// Process CSS
const result = await postcss([discardOverridden()])
  .process(css, { from: 'input.css', to: 'output.css' });

console.log(result.css);

Example transformation:

Input CSS:

@keyframes fade-in {
  0% { opacity: 0; }
  100% { opacity: 0.8; }
}

@keyframes fade-in {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

Output CSS:

@keyframes fade-in {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

Capabilities

Plugin Creator Function

The main export is a function that creates a PostCSS plugin instance.

/**
 * Creates a PostCSS plugin that removes overridden @keyframes and @counter-style rules
 * @returns {import('postcss').Plugin} PostCSS plugin instance
 */
function postcssDiscardOverridden(): import('postcss').Plugin;

The plugin creator function takes no options and returns a PostCSS plugin with the following properties:

interface PostCSSPlugin {
  /** Plugin identifier for PostCSS */
  postcssPlugin: 'postcss-discard-overridden';
  /** Plugin preparation function */
  prepare(): {
    /** Function called once at the end of processing */
    OnceExit(css: import('postcss').Root): void;
  };
}

Usage Example:

const postcss = require('postcss');
const discardOverridden = require('postcss-discard-overridden');

// Use with other PostCSS plugins
const processor = postcss([
  require('autoprefixer'),
  discardOverridden(),
  require('cssnano')
]);

const result = await processor.process(css, { from: 'input.css' });

PostCSS Compatibility

The plugin includes PostCSS compatibility markers:

/** PostCSS compatibility flag */
postcssDiscardOverridden.postcss = true;

This ensures the plugin is compatible with PostCSS's plugin system and can be used in plugin arrays.

Processing Logic

The plugin operates by:

  1. Scanning: Walking through all at-rules in the CSS AST
  2. Identification: Identifying overridable rules (@keyframes, @counter-style)
  3. Scope Analysis: Building scope chains for rules nested within @media, @supports, etc.
  4. Deduplication: Keeping only the last occurrence of each rule within its scope
  5. Removal: Removing all earlier duplicate rules

Supported At-Rules

The plugin processes these at-rule types:

  • @keyframes (including vendor-prefixed variants like @-webkit-keyframes)
  • @counter-style (including vendor-prefixed variants)

Scope Handling

The plugin respects CSS cascade rules and scoping:

  • Global Scope: Rules at the root level override each other completely
  • Media Queries: Rules within @media blocks only override in matching conditions
  • Support Queries: Rules within @supports blocks only override when features are supported
  • Nested Scopes: Complex nesting scenarios are handled correctly

Example with scoping:

/* Input */
@keyframes fade { /* ... */ }
@media (max-width: 500px) {
  @keyframes fade { /* ... */ }  /* Only overrides in narrow viewports */
}
@keyframes fade { /* ... */ }    /* Overrides global fade */

/* Output - media query version is preserved */
@media (max-width: 500px) {
  @keyframes fade { /* ... */ }
}
@keyframes fade { /* ... */ }

Integration Patterns

With Build Tools

// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  require('postcss-discard-overridden')(),
                  require('autoprefixer'),
                ]
              }
            }
          }
        ]
      }
    ]
  }
};

With PostCSS CLI

// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-discard-overridden'),
    require('autoprefixer'),
    require('cssnano')
  ]
}

Programmatic Usage

const fs = require('fs');
const postcss = require('postcss');
const discardOverridden = require('postcss-discard-overridden');

async function processCSS(inputFile, outputFile) {
  const css = fs.readFileSync(inputFile, 'utf8');
  
  const result = await postcss([discardOverridden()])
    .process(css, { 
      from: inputFile, 
      to: outputFile 
    });
  
  fs.writeFileSync(outputFile, result.css);
  
  if (result.map) {
    fs.writeFileSync(outputFile + '.map', result.map.toString());
  }
}

Error Handling

The plugin operates on the PostCSS AST and does not throw errors under normal circumstances. It gracefully handles:

  • Empty CSS files
  • Files without @keyframes or @counter-style rules
  • Malformed at-rules (passes them through unchanged)
  • Complex nesting scenarios

PostCSS-level errors (syntax errors, etc.) are handled by the PostCSS parser before this plugin runs.

Type Definitions

TypeScript definitions are available:

declare function postcssDiscardOverridden(): import("postcss").Plugin;
declare namespace postcssDiscardOverridden {
    let postcss: true;
}

export = postcssDiscardOverridden;