Home

Master css-complexity-analyzer Guide

CSS complexity analyzer transforming messy selectors into clean health metrics

Master css-complexity-analyzer: Tame Your CSS Complexity

The Problem That Keeps CSS Maintainable

Hey there, fellow developer! Ever inherited a CSS codebase where selectors look like .header .nav .menu .item .link:hover span.title? You know the pain—selectors so specific they override everything, maintenance becomes a nightmare, and nobody dares touch the styles anymore. That's where css-complexity-analyzer comes in, giving you hard numbers on your CSS health so you can refactor before it's too late.

What is css-complexity-analyzer?

css-complexity-analyzer is your CSS health inspector that parses your stylesheets and spits out 150+ metrics including selector complexity, specificity scores, duplication rates, and rule bloat. Unlike basic linters, it quantifies how bad your CSS is with stats like average selector complexity (2.0 vs 5.2) and specificity heatmaps. Think of it as CSS's equivalent of cyclomatic complexity for JavaScript—objective numbers to guide your refactoring.

Built on proven analyzers like @projectwallace/css-analyzer, it powers tools used by teams at scale to keep CSS lean and performant.

Getting Started

npm install --save-dev css-complexity-analyzer
# or yarn
yarn add --dev css-complexity-analyzer

Basic usage is dead simple:

// analyze.ts
import { analyzeCSS } from 'css-complexity-analyzer';
 
const css = `
.header .nav .menu .item.active { /* nightmare selector */
  padding: 20px;
}
 
.btn { /* clean selector */
  padding: 10px;
}
`;
 
const results = await analyzeCSS(css);
console.log('Average selector complexity:', results.complexity.mean);
console.log('Highest specificity:', results.specificity.max);
// Output: Average selector complexity: 3.2, Highest specificity: [0,4,2]

Core Feature 1: Selector Complexity Scoring

The killer feature? Selector complexity scores that tell you exactly how many browser decisions each selector requires. Complexity > 3? Time to refactor.

// complexity-example.ts
import { analyzeCSS } from 'css-complexity-analyzer';
 
const messyCSS = `
.main .content .article .header ul li a.active span.title {
  color: red;
}
`;
 
const result = await analyzeCSS(messyCSS);
 
console.log('Complexity breakdown:', {
  min: result.complexity.min,    // 1
  max: result.complexity.max,    // 8 😱
  mean: result.complexity.mean,  // 4.5 🚨
  offenders: result.selectors.slice(0, 3) // Worst 3 selectors
});

Why this matters: Browsers evaluate selectors right-to-left. .title span.active a li ul.header forces 8 DOM checks, while .title needs just a single check. High complexity = slow rendering.

Core Feature 2: Specificity Heatmaps

Get a visual (data) breakdown of your specificity wars:

// specificity-example.ts
import { analyzeCSS } from 'css-complexity-analyzer';
 
const cssWithSpecificityWars = `
/* ID overrides everything */
#hero { color: blue; }
 
/* Class soup */
.sidebar .content .post .title { color: green; }
 
/* Ultra-specific monster */
article section:nth-child(3) .card:hover .btn-primary { color: red !important; }
`;
 
const stats = await analyzeCSS(cssWithSpecificityWars);
 
console.table(stats.specificity.sum); // [0, 5, 3] = BAD
console.log('Specificity offenders:', stats.offenders?.specificity || []);

Pro tip: Aim for specificity sums under [0,2,2]. Anything higher means override hell awaits.

Core Feature 3: Duplication Detection

Find copy-pasted rules killing your bundle size:

// duplication-example.ts
import { analyzeCSS } from 'css-complexity-analyzer';
 
const duplicatedCSS = `
.btn-primary { padding: 10px 20px; border-radius: 4px; }
.btn-secondary { padding: 10px 20px; border-radius: 4px; }
 
/* Same padding/border 47 more times... */
`;
 
const analysis = await analyzeCSS(duplicatedCSS);
 
console.log('Duplicated properties:', analysis.duplicatedProperties);
console.log('Duplicated selectors:', analysis.duplicatedSelectors);
// Reveals: 47 padding instances, 12 border-radius defs

Real-World Example: Pre-commit CSS Audit

Here's a production-ready Git hook that blocks bad CSS:

// scripts/css-audit.ts
import { analyzeCSS } from 'css-complexity-analyzer';
import { readFileSync } from 'fs';
import { globSync } from 'glob';
 
type AuditResult = {
  pass: boolean;
  message: string;
  metrics: any;
};
 
const MAX_COMPLEXITY = 3.5;
const MAX_SPECIFICITY = 15; // [0,3,2] = 15
 
async function auditCSS(): Promise<AuditResult> {
  const cssFiles = globSync('src/**/*.css');
  let totalCSS = '';
  
  for (const file of cssFiles) {
    totalCSS += readFileSync(file, 'utf8');
  }
  
  const results = await analyzeCSS(totalCSS);
  
  const tooComplex = results.complexity.mean > MAX_COMPLEXITY;
  const specificityFail = results.specificity.sum.reduce((a: number, b: number) => a + b, 0) > MAX_SPECIFICITY;
  
  if (tooComplex || specificityFail) {
    return {
      pass: false,
      message: `🚨 CSS audit failed!\nComplexity: ${results.complexity.mean.toFixed(1)} (max ${MAX_COMPLEXITY})\nSpecificity sum: ${results.specificity.sum.reduce((a: number, b: number) => a + b, 0)} (max ${MAX_SPECIFICITY})`,
      metrics: results
    };
  }
  
  return {
    pass: true,
    message: `✅ CSS healthy! Complexity: ${results.complexity.mean.toFixed(1)}`,
    metrics: results
  };
}
 
// Usage: npx tsx scripts/css-audit.ts
auditCSS().then(console.log);

Add to package.json:

{
  "scripts": {
    "lint:css": "tsx scripts/css-audit.ts"
  }
}

Tips & Gotchas

Do: Run weekly on your main CSS bundle ✅ Do: Set complexity thresholds in CI (like Constyble) ✅ Do: Focus on complexity.mean > 3.0 first

Don't: Ignore !important counts—3+ is a red flag ❌ Don't: Let duplicatedProperties > 20—extract to custom properties ❌ Gotcha: Ignores CSS-in-JS. Pre-process with css extraction first

TypeScript tip: Results are Record<string, any>—use Zod for validation:

import { z } from 'zod';  
const CSSMetrics = z.object({
  complexity: z.object({ mean: z.number() }),
  specificity: z.object({ sum: z.array(z.number()) })
});

When to Use It (vs Alternatives)

Tool | Best For | vs css-complexity-analyzer

  • **css-complexity-analyzer** | Production metrics + CLI | 150+ metrics, TypeScript-ready[1]
  • `analyze-css` | Quick audits | Fewer metrics, no complexity scores[2]
  • `parker` | Basic stats | No selector complexity[8]
  • `wallace-cli` | Terminal beauty | Less programmatic API[6]

Use this when: You need programmatic access + comprehensive metrics for CI/CD.

Skip when: One-off analysis (use Project Wallace online).

Limitations

  • No CSS-in-JS support (needs extraction)
  • PostCSS-only (Sass/Less need compilation first)
  • Large CSS bundles (>10MB) can timeout

Next steps: Hook it into your PR workflow, set complexity thresholds, and watch your CSS stay maintainable forever! 🚀