or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-features.mdbatch-processing.mdcompatibility.mdconstructor-options.mdindex.mdinput-output.mdoptimization-levels.md
tile.json

optimization-levels.mddocs/

Optimization Levels

Clean-CSS provides three distinct optimization levels, each building upon the previous level to provide increasingly aggressive minification strategies.

Optimization Level Overview

interface OptimizationLevelObject {
  0?: object;         // No optimizations, basic cleanup only
  1?: Level1Options;  // Property-level optimizations (default)
  2?: Level2Options;  // Rule-level and structural optimizations
}

Level 0 - No Optimizations

Level 0 performs only basic cleanup without any optimizations. This level is useful when you want to preserve the CSS exactly as written.

const minifier = new CleanCSS({ level: 0 });

What Level 0 does:

  • Removes comments (unless configured otherwise)
  • Basic whitespace normalization
  • No property or structural optimizations

Level 1 - Property-Level Optimizations (Default)

Level 1 applies safe property-level optimizations that don't change the CSS structure or semantics.

interface Level1Options {
  cleanupCharsets?: boolean;           // Remove duplicate charset rules
  normalizeUrls?: boolean;             // Normalize URLs in url() functions
  optimizeBackground?: boolean;        // Optimize background property
  optimizeBorderRadius?: boolean;      // Optimize border-radius property
  optimizeFilter?: boolean;           // Optimize filter property
  optimizeFontWeight?: boolean;       // Optimize font-weight values
  optimizeOutline?: boolean;          // Optimize outline property
  removeEmpty?: boolean;              // Remove empty rules and blocks
  removeNegativePaddings?: boolean;   // Remove negative padding values
  removeQuotes?: boolean;             // Remove unnecessary quotes
  removeWhitespace?: boolean;         // Remove extra whitespace
  replaceMultipleZeros?: boolean;     // Replace multiple zeros with single zero
  replaceTimeUnits?: boolean;         // Replace time units (ms -> s)
  replaceZeroUnits?: boolean;         // Remove units from zero values
  roundingPrecision?: number | object; // Rounding precision for numbers
  selectorsSortingMethod?: string;    // Selector sorting method
  specialComments?: string;           // Special comment handling
  tidyAtRules?: boolean;              // Tidy at-rules
  tidyBlockScopes?: boolean;          // Tidy block scopes
  tidySelectors?: boolean;            // Tidy selectors
  variableValueOptimizers?: string[]; // CSS variable value optimizers
}

Level 1 Default Settings

const level1Defaults = {
  cleanupCharsets: true,
  normalizeUrls: true,
  optimizeBackground: true,
  optimizeBorderRadius: true,
  optimizeFilter: true,
  optimizeFontWeight: true,
  optimizeOutline: true,
  removeEmpty: true,
  removeNegativePaddings: true,
  removeQuotes: true,
  removeWhitespace: true,
  replaceMultipleZeros: true,
  replaceTimeUnits: true,
  replaceZeroUnits: true,
  roundingPrecision: false,  // Disabled by default
  selectorsSortingMethod: 'standard',
  specialComments: 'all',
  tidyAtRules: true,
  tidyBlockScopes: true,
  tidySelectors: true,
  variableValueOptimizers: []
};

Level 1 Usage Examples

// Default level 1
const minifier = new CleanCSS({ level: 1 });

// Custom level 1 with specific options
const customLevel1 = new CleanCSS({
  level: {
    1: {
      removeEmpty: false,           // Keep empty rules
      specialComments: 'none',      // Remove all comments
      roundingPrecision: 2          // Round to 2 decimal places
    }
  }
});

// Level 1 with variable value optimization
const variableOptimizer = new CleanCSS({
  level: {
    1: {
      variableValueOptimizers: ['color', 'fraction', 'precision']
    }
  }
});

Level 2 - Rule-Level and Structural Optimizations

Level 2 applies aggressive structural optimizations that can reorganize and merge CSS rules for maximum compression.

interface Level2Options {
  mergeAdjacentRules?: boolean;        // Merge adjacent rules with same selector
  mergeIntoShorthands?: boolean;       // Merge properties into shorthand
  mergeMedia?: boolean;                // Merge @media blocks
  mergeNonAdjacentRules?: boolean;     // Merge non-adjacent rules with same selector
  mergeSemantically?: boolean;         // Merge rules semantically (aggressive)
  overrideProperties?: boolean;        // Override properties with later ones
  removeEmpty?: boolean;               // Remove empty rules and blocks
  reduceNonAdjacentRules?: boolean;    // Reduce non-adjacent rules
  removeDuplicateFontRules?: boolean;  // Remove duplicate @font-face rules
  removeDuplicateMediaBlocks?: boolean; // Remove duplicate @media blocks
  removeDuplicateRules?: boolean;      // Remove duplicate rules
  removeUnusedAtRules?: boolean;       // Remove unused at-rules
  restructureRules?: boolean;          // Restructure rules for better compression
  skipProperties?: string[];           // Properties to skip optimization
}

Level 2 Default Settings

const level2Defaults = {
  mergeAdjacentRules: true,
  mergeIntoShorthands: true,
  mergeMedia: true,
  mergeNonAdjacentRules: true,
  mergeSemantically: false,     // Disabled for safety
  overrideProperties: true,
  removeEmpty: true,
  reduceNonAdjacentRules: true,
  removeDuplicateFontRules: true,
  removeDuplicateMediaBlocks: true,
  removeDuplicateRules: true,
  removeUnusedAtRules: false,   // Disabled for safety
  restructureRules: false,      // Disabled for safety
  skipProperties: []
};

Level 2 Usage Examples

// Default level 2
const level2Minifier = new CleanCSS({ level: 2 });

// Conservative level 2 (safer optimizations)
const safeLevel2 = new CleanCSS({
  level: {
    2: {
      mergeSemantically: false,
      restructureRules: false,
      removeUnusedAtRules: false
    }
  }
});

// Aggressive level 2 (maximum compression)
const aggressiveLevel2 = new CleanCSS({
  level: {
    2: {
      mergeSemantically: true,
      restructureRules: true,
      removeUnusedAtRules: true
    }
  }
});

// Level 2 with property skipping
const skipPropertiesLevel2 = new CleanCSS({
  level: {
    2: {
      skipProperties: ['font-family', 'background-image']
    }
  }
});

Combined Level Configuration

You can combine multiple optimization levels for fine-grained control:

const combinedLevels = new CleanCSS({
  level: {
    1: {
      removeEmpty: true,
      specialComments: 'none',
      roundingPrecision: 2
    },
    2: {
      mergeAdjacentRules: true,
      mergeIntoShorthands: true,
      mergeSemantically: false
    }
  }
});

Rounding Precision Configuration

/**
 * Rounding precision configuration for different unit types
 * @typedef {object} RoundingPrecisionOptions
 * @property {number|'off'} [ch] - Character unit precision
 * @property {number|'off'} [cm] - Centimeter unit precision
 * @property {number|'off'} [em] - Em unit precision
 * @property {number|'off'} [ex] - Ex unit precision
 * @property {number|'off'} [in] - Inch unit precision
 * @property {number|'off'} [mm] - Millimeter unit precision
 * @property {number|'off'} [pc] - Pica unit precision
 * @property {number|'off'} [pt] - Point unit precision
 * @property {number|'off'} [px] - Pixel unit precision
 * @property {number|'off'} [q] - Quarter-millimeter unit precision
 * @property {number|'off'} [rem] - Root em unit precision
 * @property {number|'off'} [vh] - Viewport height unit precision
 * @property {number|'off'} [vmax] - Viewport maximum unit precision
 * @property {number|'off'} [vmin] - Viewport minimum unit precision
 * @property {number|'off'} [vw] - Viewport width unit precision
 * @property {number|'off'} ['%'] - Percentage unit precision
 * @property {number|'off'} ['*'] - Default precision for all other units
 */

Configure decimal precision for different unit types. Set to 'off' to disable rounding for specific units:

const precisionConfig = new CleanCSS({
  level: {
    1: {
      roundingPrecision: {
        'px': 0,        // No decimals for pixels
        'em': 3,        // 3 decimals for em units
        'rem': 3,       // 3 decimals for rem units
        'vh': 2,        // 2 decimals for viewport units
        'vw': 2,        // 2 decimals for viewport units
        'vmin': 2,      // 2 decimals for viewport units
        'vmax': 2,      // 2 decimals for viewport units
        '%': 2,         // 2 decimals for percentages
        'pt': 1,        // 1 decimal for points
        'pc': 2,        // 2 decimals for picas
        'in': 3,        // 3 decimals for inches
        'cm': 2,        // 2 decimals for centimeters
        'mm': 1,        // 1 decimal for millimeters
        'q': 0,         // No decimals for quarter-millimeters
        'ch': 2,        // 2 decimals for character units
        'ex': 2,        // 2 decimals for ex units
        '*': 'off'      // Disable rounding for all other units
      }
    }
  }
});

Unit-Specific Examples:

// Absolute length units
const absoluteUnitsConfig = new CleanCSS({
  level: { 1: { roundingPrecision: {
    'px': 0,     // 16.75px → 17px
    'pt': 1,     // 12.345pt → 12.3pt
    'pc': 2,     // 1.2345pc → 1.23pc
    'in': 3,     // 0.12345in → 0.123in
    'cm': 2,     // 2.5467cm → 2.55cm
    'mm': 1,     // 25.67mm → 25.7mm
    'q': 0       // 102.5q → 103q
  }}}
});

// Relative length units
const relativeUnitsConfig = new CleanCSS({
  level: { 1: { roundingPrecision: {
    'em': 3,     // 1.23456em → 1.235em
    'rem': 3,    // 0.87654rem → 0.877rem
    'ch': 2,     // 4.567ch → 4.57ch
    'ex': 2      // 2.345ex → 2.35ex
  }}}
});

// Viewport units
const viewportUnitsConfig = new CleanCSS({
  level: { 1: { roundingPrecision: {
    'vh': 2,     // 12.345vh → 12.35vh
    'vw': 2,     // 50.678vw → 50.68vw
    'vmin': 1,   // 10.567vmin → 10.6vmin
    'vmax': 1    // 90.234vmax → 90.2vmax
  }}}
});

Selector Sorting Methods

Control how selectors are sorted within merged rules:

const selectorSorting = new CleanCSS({
  level: {
    1: {
      selectorsSortingMethod: 'alphabetical'  // 'standard', 'alphabetical', 'none', false
    }
  }
});

Special Comments Handling

Control how special comments are handled:

const commentHandling = new CleanCSS({
  level: {
    1: {
      specialComments: 'all'     // 'all', 'none', '1', '0'
    }
  }
});
  • 'all': Keep all special comments
  • '1': Keep first special comment only
  • '0' or 'none': Remove all comments
  • Number: Keep that many special comments