Mutually exclusive selectors

How you can avoid overrides and live without the specificity hell

Hajime Yamasaki Vukelic
3 min readJan 26, 2023
Photo by Alice Yamamura on Unsplash

Over the years, developers have come up with various creative (and not so creative) ways to avoid the specificity hell. In this short article, I will share with you a trick that will allow you to avoid specificity conflicts in those cases where dealing with them the usual way would result in unnecessarily complicated selectors.

Specificity hell

Alright, calm down now. There’s no “hell” in front end development. There’s just lack of experience and/or knowledge. Both easily fixed by gaining what’s missing. I promise you that. “Specificity hell” is just a phrase I used to grab your attention. In real life, specificity conflicts are not that common, especially if you learn how specificity works.

It’s mostly just an odd case here and there, where you find yourself unable to override some style because of a high-specificity selector you used somewhere else. If you’ll excuse my pulling out a number from behind me, it happens roughly 1 out of 76 times. Or was it 67… Anyway, it’s rare, that’s the point.

Here’s an example that I made-up for this article. It’s deliberately simple to demonstrate the concept and it may not be quite obvious why you’d need a different solution until you actually learn you do in real life, so please bear with me. 🐻

First the HTML:

<ul id="articles">
<li class="active">
<h2>Specificity hell</h2>
<p>Published on: Feb 12, 2005</p>
<a href="/specificity-hell.html">Read the article</a>
</li>
<li class="archived">
<h2>How important is !important?</h2>
<p>Published on: Feb 10, 2005</p>
<a href="/how-important-important.html">Read the article</a>
</li>
<li>
<h2>Stop nesting selectors in 2005!</h2>
<p>Published on: Jan 12, 2005</p>
<a href="/stop-nesting-selectors-2005.html">Read the article</a>
</li>
</ul>

The CSS for this page fragment looks like this:

#articles li {
background: #ffe;
}

.active {
background: #faf;
}

.archived {
background: #aff;
}

As you may have noticed, the second declaration block will not apply because the selector #articles li is more specific than .active and .archived.

Now, I won’t go into the whole “why” it is more specific etc. That’s not the point. Instead, I will show you how to avoid this kind of conflict without tweaking the specificity.

In this particular case, tweaking specificity is not that hard, so let me just show you real quick before we move on:

#articles li {
background: #ffe;
}

#articles .active {
background: #faf;
}

#articles .archived {
background: #aff;
}

The mutually exclusive selectors

Specificity conflicts occur only when we have the same element targeted by two different selectors at the same time. The solution? Stop targeting the same element with multiple selectors (sometimes). Thanks to the :not() pseudo-class, this is quite trivial to achieve, too.

I call this technique “mutually exclusive selectors” or MESs for short. 🤣

In our case, an article cannot be both .active and not .active at the same time, but the #articles li selector applies in both cases. We can cleanly separate these two cases in CSS with this small tweak:

#articles li:not(.active, .archived) {
background: #ffe;
}

.active {
background: #faf;
}

.archived {
background: #aff;
}

And that’s it. With this little trick, we are no longer concerned with the specificity of the selectors. The specificity of the first selector in fact even increased, but the other two declaration blocks will still be applied.

When to use these

It is not necessary to always default to using these. While the above example is obviously rigged to necessitate them, we were still able to take care of that problem without using the MESs. Specificity is OK (or at least manageable) in small quantities, and not worth eliminating at all costs (I can already see the BEM crowd getting their .shed--wall--pitchfork__stored out).

I find that this trick is most effective when used as needed, as you run into (or reasonably foresee) the issues. Don’t turn it into a religion, now!

--

--

Hajime Yamasaki Vukelic

Helping build an inclusive and accessible web. Web developer and writer. Sometimes annoying, but mostly just looking to share knowledge.