css specificity issues

One of the core basics of css is its set of specificity rules. Most of the time css specificity works well, as long as you purposely describe the elements you want to target (something to remember when refactoring css selectors), but there are some underlying flaws in the concept that could do with a little extra attention. Situations where the mind assumes things that cannot be expressed in css, often wielding unexpected or unfavorable results.

components and component variations

I've tackled issues with specificity before in an older article on css specificity lacking proximity, this time around I would like to elaborate on a more specific problem that is directly related to the way we interpret and compose html components. And of course the way we (try to) translate them into valid css rules.

<div class="spec date">...</div> <div class="spec author">...</div>

Looking at the code above, everyone will immediately understand that .spec is the base class (or the component class) while .date and .author indicate semantic variations of the .spec component (I typically use the .spec class for a single label/value pair). The fact of the matter is that there is absolutely no way at all to express this in css, unless by convention.

.spec.date .spec.author

Because we place the .spec class first (both in html and css) it becomes clear that it is the component class, but in no way does it change anything about weight and preference when two selectors are fighting for dominance. And that's exactly what can be so confusing. For a first example (and an in-depth look at some less than stellar solutions) you can read an older post on specificity issues, below I will detail a second example.

states and variations

Imagine having a website that has a few color-coded sections (just like mine really). You have additional sub navigation in each section that is designed in the color of the section it resides in. The design is exactly the just, just the link color differs depending on what section you're in. The problem is that you don't really want to change the appearance of your active states (current page) across the different sections.

<nav class="sub [varX]"> <ul> <li>...</li> <li class="active">...</li> </ul> </nav>

Before continuing with the css, two small html remarks: in real life you would probably put a body class to mark a specific section, but to make the example a little easier to understand I've added a variable class on the nav element itself, describing the section variants. Another reason for doing this is to make clear that you can't always rely on other (contextual) classes to add some extra weight to a selector.

Then there is the active class, which indicates which navigation item is currently active (what's in a name). Usually the code inside a li.active differs from the other list items as the link itself will be taken off the navigation item (why link to yourself right), let's assume the CMS (or the budget) didn't allow for that this time around. Not such a big stretch, is it?

.nav ul li.active a {display:block; background:#fff; color:#333;} /* section variations */ .nav.var1 ul li a {background:#f09; color:#fff;} .nav.var2 ul li a {background:#dd0; color:#fff;}

The css code above properly illustrates the problem. Even though we set a global active class, the styling is being overwritten by the component variations, even when we don't want it to. The .active class functions as a cross-variation state, but css doesn't know that and there is no way to express it either. All it does is compute weight, so the variant class is considered equally important as the state class and wins out when properties have conflicting values.

conclusion

It's important to remember that even though we mentally separate class names in different groups (components, component variants, states, layout), css itself does not. All classes are considered equal in css and they are handled that way. This can lead to some confusion and to less than favorable solutions trying to fix unexpected problems. For now there's little that can be done and I'm not even sure if something should be done about it (it's the simplicity and extendibility of classes that made css what it is today), but it is a flaw that has persisted since css made its way into the mainstream and it could do with some extra attention.

If I missed any obvious fixes or workarounds, do let me know.