Avoiding specificity issues in CSS

Holy moly. What a discussion we’ve gotten into over on Twitter about CSS specificity, BEM, and inheritance. I wrote yesterday that the idea is flawed and tries to work around problems which aren’t actually problems at all, but part of the language of CSS. As Duncan noted: the problem is actually, “people write bad CSS”.

Dirk from the DECAF agency in Berlin responded with a blog post, which summarizes the opposing point of view. And away we went.

The summary of the discussion points which came back relate to overcoming specificity issues in CSS. Say you define #content div {width: 600px;} high up in your CSS. Then, lower down, you want to set div.subtext {width: 580px;}, where this DIV is within the #content element. You’re stuck: the #content div rule is more specific, thanks to the use of an ID. So you have to work around the problem by forcing your later rule to take affect with the use of !important. *Shudder*.

That’s an awful way to go about writing CSS, not a problem with CSS itself. The right way to define these rules is to use class selectors.

.content div {width: 600px;}
.content div.subtext {width: 580px;}

There are three basic steps which you can take when starting to write CSS which will stop this kind of problem from ever occurring, and which will help you to write less code, encounter far fewer specificity problems, and make the world a happier place. (Maybe.)

  1. Never use IDs for layout. Never. You don’t need them. Using an ID is acceptable if you need to set an anchor in the page, or (in some cases) to interact with elements using JavaScript. You never need use an ID in CSS. Never.
  2. Separate your CSS logic into definitions for HTML element tags where rules apply to all such elements. All H3 elements should be bold; all P elements have a 1em margin, and so on. Then use class names for more specific definitions.
  3. Anything relating to a component on the page should be handled with classes or with attribute selectors. Use a separate class for each layout feature you want to apply. Use .highlight to apply a yellow background, .border to add a border to an element, .animate to use CSS’ transition properties.

If you want to add a set of rules for your own component, like an image slider, use a master class name like .cmp-slider and then use CSS’ parent-child logic to style the child elements within the master class.

(Later, when web components are introduced, the same idea applies. Just using a HTML tag like <cmp-slider></cmp-slider> instead of <div class="cmp-slider"></div>.)

That’s how CSS is designed to be used, and it’s taken over twenty years’ work by thousands of people to get to its current state. Before you start learning or inventing ways to work around the problems you encounter regularly, make sure that they’re not based on a misunderstanding of the implementation, rather than an assumption that the problems are unsolvable without a new framework or a new bolt-on addition.