CSS Specificity Isn't Your Biggest Problem
Also available in Español The Problem A team ships clean CSS. Every selector is deliberate. Every class name means something. Code review catches the sloppy stuff before it merges. Six months later, someone adds !important to fix a button. A year later, three more !important s exist — each one written to fix the last one. Nobody planned this. Nobody stopped caring. The team is exactly as disciplined as it was on day one. The codebase didn't get sloppy. The architecture never had a way to stay clean. That's the part worth sitting with. Specificity problems get treated as a discipline failure — bad naming, careless nesting, someone in a hurry. But teams with excellent discipline hit this wall too. Given enough time and enough contributors, almost every CSS codebase drifts toward the same place: overrides stacked on overrides, each one a patch for the last. Something structural is happening here. Not a people problem. A tooling gap. Why the Problem Exists CSS specificity was built to answer one narrow question: if two rules target the same element, which one wins? The browser calculates an answer. Count the IDs. Count the classes and attributes. Count the elements. Higher count wins. If the count ties, whichever rule appears later in source order wins. That's the entire mechanism. It's fast, deterministic, and was never meant to do more than that. Notice what it doesn't ask. It doesn't ask whether a rule is a foundational default or a one-off exception. It doesn't ask whether a rule was written to be overridden, or written to never be touched again. It doesn't know the difference between a base style and a utility class — it only knows how many selectors each one used. Specificity resolves conflicts. It was never given a way to encode intent. That gap is old. It predates component-based frontend architecture, design systems, and teams of a hundred engineers touching the same stylesheet. The web platform gave developers a scoring system for which rule wins by the number