Selector Specificity with CSS Preprocessors

Originally published at: http://www.sitepoint.com/selector-specificity-css-preprocessors/

Selector specificity is a real problem for most medium and large-sized projects, and as any other frequently recurring coding problem it needs to be addressed carefully. Even CSS-Tricks recently had an article on how to keep your CSS specificity low.

And before you even try to say !important let me remind you that:

CSS/everyday tip: if everything is !important, nothing is !important.

– Tony Nelson (@tonynelson19) November 18, 2010

CSS specificity isn’t that complex, but the community has done a lot to make it as easy to comprehend as possible, writing guides by using analogies with fish and Star Wars, or by using poker terminology. There are interactive calculators available online, and even a specificity mixin for Sass, allowing you to check and output the exact specificity value of a selector.

Simpler is better when in comes to a CSS specificity strategy, the specificity workarounds in this article (which may feel a bit hacky) are suited for cases where the architecture doesn’t allow for a simple fix. Use your judgment when deciding which approach suits your project best and ultimately try to hit the perfect balance between clean and maintainable CSS.

Approach #0 – BEM

BEM is more than a naming convention, it is a front-end toolkit invented by Yandex, the philosophy of which is to get closer to object-oriented programming. In practice, this means using a class name for every single thing that you style. Although “no cascading in Cascading Style Sheets” may sound preposterous to some, the idea to never use type selectors and to avoid nesting is extremely helpful when creating modules that should be maintainable, portable, self-sufficient, easy-to-modify, and scalable.

Continue reading this article on SitePoint

Approach #3: keep your CSS simple!
For most sites you shouldn’t need CSS files exceeding, say, 30Kb in total (uncompressed).

“Simpler is better” probably aligns with your third approach to “keep your CSS simple”.

Thanks for the shout-out, @futekov! I agree with your viewpoints that specificity is not complicated (at all - it’s just counting), and that BEM is not a bulletproof answer to specificity woes.

Yes, BEM is not the silver bullet for all projects but it’s still a great methodology, I personally use it as a naming convention in most things I write.

Happy counting :smile:

My main problem with many of these CSS approaches is that they apply a multitude of classes to almost every HTML element. While that helps from a conceptual and modularization point of view, it bulks up your code and I’ve rarely found it necessary - even on larger projects.

Personally, I prefer to take advantage of specificity instead of using BEM - it’s much, much simpler and less verbose, and more expressive. There are many possible relationships in CSS:

  • .parent > .child
  • .ancestor .descendant
  • .sibling ~ .sibling
  • .sibling + .adjacent-sibling
  • .sibling + * ~ .non-adjacent-sibling
  • .parent > * > .grandchild
  • .parent > * .non-child-descendant
  • .uncle ~ * > .cousin
  • * + *, the any-adjacent-sibling relationship, or lobotomized owl selector

… and BEM can’t cover all of them. The specificity of a target simple/compound selector in a relationship is also automatically greater than the specificity than the standalone simple/compound selector, which is desirable.

1 Like

Approach #2 is opening up the door to a whole new world of hurt. Someone somewhere would eventually:

@mixin alwaysOnTop($i) {
    @include specificity(9999 + $i) {
        position: fixed;
        z-index: 9999 + $i;
    }
}

.modal {
    @include alwaysOnTop(9999);
}

Reducing specificity is also a fine way to encourage sloppy HTML. For example, if my CSS selector was more self-documenting e.g:

ul[role="tablist"] li[role="tab"][aria-labelledby] a[id]

That might seem like overkill, but CSS written like this will enforce quality gates by refusing to style content that doesn’t meet project standards. Large projects need to do this, not employ workarounds.

Another benefit of self-documenting CSS selectors is that a test page can be automatically generated more robustly and reliably than from a CSS only containing out-of-context class selectors.

@shannonmoeller Hopefully people won’t abuse this mixin as they do z-index values, this shouldn’t become a new !important, it should be carefully used only when needed.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.