Fossils🧠 ConceptualCSS Specificity & Architecture
ðŸĢHatchlingCSSArchitectureFundamentals

CSS Specificity & Architecture

CSS specificity is a scoring system, not magic. Understanding it — plus modern CSS architecture — separates engineers who fight CSS from those who wield it.

CSS Specificity & Architecture

Interview Question: "How does CSS specificity work? How do you architect CSS at scale?"

Specificity: The Scoring System

"Specificity is a four-part score: (inline, IDs, classes/attributes/pseudo-classes, elements/pseudo-elements). Higher score wins. In case of a tie, the last rule in source order wins."

SelectorSpecificityScore
*(0,0,0,0)0
div(0,0,0,1)1 element
.card(0,0,1,0)1 class
#header(0,1,0,0)1 ID
style=""(1,0,0,0)Inline
div.card.active(0,0,2,1)2 classes + 1 element
#nav .link:hover(0,1,2,0)1 ID + 1 class + 1 pseudo-class

The Rules

"Each category is independent — 256 classes cannot outweigh a single ID (in practice; technically it depends on the browser's implementation, but treat them as separate columns). !important overrides everything except another !important with higher specificity. The cascade order: user-agent → user → author → author !important → user !important."

:where() vs :is()

/* :is() — takes the highest specificity of its arguments */
:is(.card, #hero) .title { color: red; }  /* Specificity: (0,1,1,0) — ID wins */
 
/* :where() — always zero specificity */
:where(.card, #hero) .title { color: red; }  /* Specificity: (0,0,1,0) — reset! */

:where() is a game-changer for library CSS — it applies styles without increasing specificity, making overrides easy for consumers.

CSS Layers (@layer)

@layer base, components, utilities;
 
@layer base {
  h1 { font-size: 2rem; }
}
 
@layer components {
  .card h1 { font-size: 1.5rem; }
}
 
@layer utilities {
  .text-xl { font-size: 1.25rem !important; }
}

"Layers establish explicit specificity ordering regardless of selector complexity. Utilities layer always beats components, which always beats base. This is how Tailwind CSS v4 works under the hood."

CSS Architecture at Scale

The Problems

  • Specificity wars — Every new feature needs more specific selectors
  • Global scope — All CSS is global, names collide across teams
  • Dead code — Unused CSS accumulates, can't safely delete
  • Inconsistency — 47 shades of gray, 12 spacing values

Solutions Comparison

ApproachScopeDead Code DetectionTrade-off
BEMConvention-basedHardVerbose class names
CSS ModulesFile-scoped (build tool)Easy (per component)Requires build step
Tailwind CSSUtility classesAutomatic (purge)HTML verbosity
CSS-in-JSComponent-scoped (runtime)AutomaticRuntime cost, SSR complexity
CSS LayersExplicit orderingManualBrowser support

Modern Recommendation

"For most React apps: CSS Modules or Tailwind for component styling, with a design token system (CSS custom properties) for consistency. CSS-in-JS (styled-components, Emotion) has fallen out of favor due to runtime overhead and SSR complexity."

/* Design tokens via custom properties */
:root {
  --color-primary: oklch(0.7 0.15 250);
  --spacing-4: 1rem;
  --radius-md: 0.5rem;
  --shadow-sm: 0 1px 2px oklch(0 0 0 / 0.05);
}

Red Flags

  • Not knowing the specificity scoring system
  • Using !important as a first resort instead of fixing specificity
  • Not knowing modern solutions (CSS Modules, Layers, :where())
  • No opinion on CSS architecture for large teams