Keeping CSS specificity low across all the selectors in your project is a worthy goal. It’s generally a sign that things are in relative harmony. You aren’t fighting against yourself and you have plenty of room to override styles when you need to. Specificity on selectors tends to creep up over time, and there is a hard ceiling to that. I’m sure we’ve all felt the pain of !important tags and inline styles.
So how do we keep that specificity low over time?
Give yourself the class you need
Perhaps you’re writing a high-specificity selector because you’re overriding an already-existing selector. Maybe the element you’re trying to select is included on multiple pages, so you select it from a higher-up class:
.section-header {
/* normal styles */
}
body.about-page .section-header {
/* override with higher specificity */
}
However you feel about this, recognize that that specificity is creeping up here. To prevent this, is there a way you can alter the class name on that element you’re trying to style directly instead? Sometimes creating some server side helper functions or variables for emitting classes can be helpful, to avoid logic in views.
<header class="<%= header_class %>">
Which could output one class, or both, as desired.
</header>
.section-header {
/* normal styles */
}
.about-section-header {
/* override with same specificity */
/* possibly extend the standard class */
}
Consider the source-order of the stylesheets
Along that same trying-to-override-something vein, perhaps you are applying an additional class name to handle a style override for you.
<header class="section-header section-header-about">
</header>
But where you are writing your override styles with .section-header-about
are actually getting overridden by the existing class. That can happen because of selector order in the stylesheet. Both selectors have the exact same specificity, so the rules from whichever one is declared last win.
Fixing that means just ensuring that where ever you write your override class comes later. Perhaps organize your stylesheets something like:
@import "third-party-and-libs-and-stuff";
@import "global-stuff";
@import "section-stuff";
@import "specific-things-and-potential-overrides";
Reduce the specificity of the thing you’re overriding
You know what they say about leaving things better than you found them. You should do that.
If there is an ID on an element and that’s what it’s being styled by, can you remove it? Definitely do a project-wide search for #that before you do it. It might be being used as a JS hook (perfectly fine) in which case you should leave it alone and either add a class or use a class already on it for the CSS.
Don’t avoid classes to begin with
I’ve been known to use a selector like:
.module > h2 {
}
That’ll work fine, until they day you want a special style for that h2 element. You might go in your your markup and be like:
<div class="module">
<h2 class="unique">
Special Header
</h2>
</div>
But sadly:
.module > h2 {
/* normal styles */
}
.unique {
/* I'm going to lose this specificity battle */
}
.module .unique {
/* This will work, but specificity creep! */
}
The specificity creep is happening because the original selector is biting us. That’s why almost all CSS methologies recommend flat structures in the vein of:
<div class="module">
<h2 class="module-header">
</h2>
<div class="module-content">
</div>
</div>
It can feel like more tedious work up-front because you might not need those classes right away. But by not avoiding that work (don’t be lazy!), the hooks you’ll have later can save your grief.
Use the cascade
As a project ages, it becomes more and more dangerous to alter selectors with low specificity, because they potentially can affect more things and have unintended consequences.
#im #just .gonna[do] .this .to .be #safe {
/* cries (ಥ_ʖಥ) */
}
But affecting more things is the power of CSS. Having a solid base you’re building from hopefully means less overrides are ever necessary. The strategies for this can be things like…
Use a pattern library and/or style guide and/or atomic design
A pattern library (something like this) can mean you have what you are looking for when you need it. Need some tabs? Here you go, this is the established way for doing that. And it’s likely built in such a way the specificity is already light, so overriding won’t be overly difficult.
Atomic design (book) can guide how your site (or the pattern library) is built, so even if you don’t have a full pattern for what you need, you have the building blocks below it.
A style guide might save you, because it might enforce specific rules about specificity, in an attempt to save you from yourself.
Consider opt-in typography
At the same time you’re trying to use the cascade and have smart defaults for lots of elements, you might want to scope some of those smart defaults sometimes. For instance, a list element is often used for navigation and within content. The styles for them will be drastically different. So why not start with a clean slate and apply text styling only when needed.
/* reset styles globally */
ul, ol, li {
list-style: none;
margin: 0;
padding: 0;
}
/* scope text styles to text content */
.text-content {
h1, h2, h3 {
}
p {
}
ul {
}
ol {
}
/* etc */
}
That does increase the specificity of those text selectors, but it means that rules specifically for text aren’t affecting more than they need to be and there is less need for overrides.
Outside of your control issues
Perhaps some third party code expects or injects certain HTML onto your page. You have to work with that. You can still try and use as low specificity selectors as you can. You can leave comments in the code indicating why the selectors are like this. You can use low specificity selectors, but use !important overrides. You can ask the people responsible for the non-ideal code if they can fix it.
Only up the specificity lightly, and note it
If you need to get into a specificity fight, rather than reaching for a sledgehammer like an ID or !important, trying something lighter.
A tag-qualifier is the minimum possible specificity upgrade.
ul.override {
/* I win */
}
.normal {
}
But limiting a selector to a specific tag is a weird limiting factor. Might be smart to just add an additional class instead. If another name doesn’t make sense, you can even use the same class if needed.
.nav.override {
}
.override.override {
}
.nav {
}
Just because nesting is nice, it doesn’t mean specificity has to go up
Nesting in preprocessors is sometimes discouraged because it makes it so easy to write overly selectors. But nesting is sometimes just visually nice in the stylesheet, because it groups things together making it easier to read and digest.
Bohdan Kokotko reminded me recently the ampersand in Sass can be used to essentially do namespacing rather than compound selectors.
.what {
color: red;
&-so {
color: green;
&-ever {
color: blue;
}
}
}
.what {
color: red;
}
.what-so {
color: green;
}
.what-so-ever {
color: blue;
}
The single-class wrapper
A rather forceful way to handle an override is use an existing wrapping element over the area you need to apply style overrides to, or add a new one.
<div class="override">
... existing stuff ...
</div>
You now have the ability to override any existing style in there by only adding a single class to the selector. It’s specificity creep, but an attempt at keeping it low.
.override .existing {
}
Only once
If you’re ever overriding an override, that’s a good place to stop and re-consider.
Can you give yourself just a single class that you can use instead? A single override can actually be efficient, like a variation on a pattern instead of creating a new pattern. An override of an override is a recipe for confusion and further fighting.
Just do better next time
If you’ve been bitten by specificity problems, even if fixing them is impractical right now, at least you know now that it’s problematic and can approach things differently next time.
I make heavy use of the ampersand in my Sass, combined with BEM it makes it much easier to keep the specificity down to a minimum, and for me at least, it makes for better readability as children appear nested. I tend to make more use of source order for overrides. Of course this isn’t always possible for all cases but I think it’s a good thing to aim for on a general basis.
As Harry Roberts mentioned also, the specificity in a stylesheet should gradually increase, this in turn also makes managing specificity, especially when it comes to long term projects far more straightforward.
Nice, didin’t know that was even possible oO. Though you could online combine other selectors with ampersand.
The tradeoff with
&-class
approach is you lose find-in-place functionality for your given IDE. So when someone new to the team or whom hasn’t touched that part of your source is trying to debug a given module with.element-sub-sub-name
and find-in-place returns 0 results, your best bet is to provide a source map that will help trace those instances and debug them.That’s a valid point. I think though if your code is very modular each module split into separate appropiatley named files and you don’t nest your BEM more than 3 deep. Then I don’t think it should be so hard to find what the’re looking for.
I tend to comment each block like this
This way you can just search the project with #BLOCK-NAME to locate that file and in most cases you can quickly see the descendants. If the module has much complexity then you can always add some description to it.
This could be looked at as over-engineering, and it’s still something I’m experimenting with, but so far it has served me well but I am always open to other suggestions.
Another great article Chris. Thanks. I particularly like the Sass namespacing, I’d not seen that before and I’m going to try it now.
I’d be concerned to see server-side logic building the class list for the HTML, as it more tightly couples the front-end and server code. It seems to break the separation of concerns because the server logic will have an effect on style and presentation.
That said, I can totally see why it might be the path of least resistance in an existing project where the other options you list don’t work for whatever reason.
Another useful thing to note is you can increase specificty without adding additional classes or qualifying selectors (What if the element were to change??
We can just chain the same class.
so
can be selected like this
and it would have the selector weight of 3 classes in this case.
I would in most cases try to avoid this, but cases arise where it is a sensible solution.
Sorry Chris already mentioned this in the original post. Still it’s neat :)
That’s a very interesting technique. I’m not entirely sure what cases would require you to do this though — do you have any scenarios you have faced that have required this?
Not so often but if you are having some kind of specificity clash with that classname, you can just give it a little specificity boost without adding an extra classname to the markup, or tying it to a particular element.
Great article, I’ve never seen the .selector.selector thing before to slightly increase specificity.
I like the idea of
I’ve recently started using double slashes for classes used to modify existing classes with the existing class before the double slash. For example:
This keeps it pretty clear what classes your modifying classes are related to if they happened to get separated within the stylesheet, and keeps specificity nice and low.
Great ideas as usual Chris!
A bit of a tangent but with respect to source-order, I don’t understand why it’s hard to determine the actual processed order of stylesheets from a browser like Google Chrome. Obviously one can look directly at the source but often on larger projects there can be a mess of individual sheets involved.
The only way I’ve seen to get a simple list is with a snippet run in console:
Thanks Chris. Great article as always :)
This site – http://cssstats.com/ – create a nice graph (among other things) about specificity of your code.
That’s a neat tool. Thanks for the heads-up!
It’s ugly, but using attribute selectors instead of class names or id’s also lowers specificity.
Correction: attribute selectors and class selectors have the same specificity (010). The trick you’re mentioning is only true for selecting with an id.
Superb article Chris !
I wonder how many folks might find these approaches to be really useful.
And thanks for the mention, this means a lot;)
CSS Frameworks can be (and this may be more attributable to how people use them than the frameworks themselves) overly paranoid in the Cascade part of CSS. “Specificity is too difficult to manage so we’re going to dump everything and use a single class and embed the DOM in our class name.” With SASS (and Less) your source code can be relatively DRY thanks to
&extend
and compression will smear out most of the extra bytes.The problem I have is that too often we are not looking at enough of the problem.
Part of the problem is that we are combining too many properties into the same selector. Take the example of
.module > h2
. It is entirely reasonable to set things like padding and margin on it since that is going to be something that is the responsibility of the module. Having.module-h2
or some such isn’t necessarily helping a whole lot, in this case.If you’re setting something like colors and fonts as well, you’re probably doing too much in that selector and really what you want is
.default-story-heading
or something and then.unique-story-heading
. Setting padding and margin in these classes would likely be inappropriate unless you intend it to only be used in a module in which case.module > .unique
is right since it prevents someone from inadvertently using it in a place you didn’t intend. Or if you intend it to be used in multiple places, but when its in a module to also change its positioning (or what have you) then two selectors (.unique
and.module > .unique
) is appropriate just put the common stuff (color, font, what have you) in the first and the specific stuff (padding, margin) in the second.We are also making too frequent use of short hand properties. Its rare that you would set the left padding without also caring about the top padding, but I can’t count the number of times I’ve discovered that someone used
background: red
and blew away the png I wanted to show so now I have to work around it.So yes we need to be mindful of the specificity and only increase it when necessary. We also need to break up properties into multiple selectors of the appropriate specificity. We also need to be careful to only set those properties we intend to set and nothing else.
Wrong.
@Adam – exactly right. +1
Some solid tips, thanks for putting this together.
@at-root is another tool you can use to yank a nested rule back out to the root of your selectors. This keeps specificity low whilst providing the visual benefits of seeing nested hierarchy in your sass file.
.nested { @at-root { .nested-override { … } } } compiles to
.nested {} AND
.nested-override { … }
Example for:
This is too specific:
This is better:
Oh, sorry. Please remove/ignore that
nav ul li a:hover {}
line.Then, for coloring the anchors, don’t do this:
but:
It is not better. For instance if i want to use the type of list defined in nav ul {} again outside of nav ul{}, I would have to copy and paste that code or add another selector after the coma. It creates duplicate css or is too coupled.
It’s just example of simple navigation markup. It depends on your needs. You are free to give more specific classes for each list you have.
Note: I do not know whether
<nav>
’s that contains multiple direct children of list element are valid or not.Very useful advise! As it happens I’m doing an exercise at work to reduce the weight of our stylesheets and I’m dropping a lot of the selectors that are in the current sheets.
I don’t have access to change the HTML at all so have to use what’s already there. This does mean that sometimes I’m having to use IDs or 2 classes plus the element selector, but where possible I’m trying to do it with just the single class. I’m also looking at where the element appears on the page and resequencing the code based on the HTML document; that way I know I can use a more generic selector higher in the document and save the more specific ones for when they’re actually needed.
It’s a fun exercise, actually; taking the CSS of a large site (think enterprise level e-commerce) and rewriting it to lower specifity and/or file size. It’s made me want to learn SASS or LESS, and it’s shown me how to be economic in what I’m writing. Before, with smaller sites, I’d be a bit more comfortable using a certain selector, but now I’m thinking “What problems can this one cause later on?”
Very useful information, thanks for sharing.
I recently wrote on specificity graph http://josephrex.me/specificity-wars/. It’s really becomes a war especially on platforms like WordPress when a plugin clashes with a theme style rules. My just finished blog design has a moderately sweet graph here: https://gist.github.com/bl4ckdu5t/9bda2e463d96f75d7932
This is a thought provoking blog Chris, though it makes me wonder about the following quandary that I seem to be in:
Personally I have been using a lot of nested relationships in my css. The reason was so that I would refrain from modifying the html “presentation layer” in the very same way that we moved away from using javascript in that manner.
The one big question I would have because of this blog would be, with the use of more generalized classes in your document, doesn’t that significantly add to the html page weight via the class naming system in both the html and css, e.g.
in a way that using nested css relationships would end up as less code overall? e.g.
-or even-
It got me thinking a lot about how we can try to still be extensible with our code, but also how that relates to simplification and performance considerations and I’m just wondering what your thoughts were on that kind of difference?
I will point you at the module rules of the SMACSS https://smacss.com/book/type-module
FYI, it looks like there’s a problem with one of your examples. In the “The single-class wrapper” section it looks like a chunk of HTML got rendered as …existing stuff… instead of displaying the code.
Great article, Chris! I didn’t know about the namespacing feature of Sass, nor had I ever thought of the trick of duplicating the same classname in the selector. Sneaky. :-)
We’ve achieved good results using a CSS nameing scheme that follows the hierarchical nature of HTML with divides the CSS/HTML into the implemented components, subcomponents, … and so on.
Everything that is an Aimeos web shop component is covered by the CSS class “.aimeos”, the single components are named after the code parts (“.catalog-filter”) and subcomponents are more specific (“.catalog-filter-tree”):
You can find the complete CSS at https://github.com/aimeos/arcavias-core/blob/master/client/html/themes/elegance/aimeos.css
The only thing that makes problems is if your CSS classes are too unspecific like “.container”, “.name”, etc. It’s likely that they will also be defined somewhere else.
Hi Chris, I think you’ve got a typo in “Nesting in preprocessors is sometimes discouraged because it makes it so easy to write overly selectors” – do you mean ‘Nesting in preprocessors is sometimes discouraged because it makes it so easy to write overly [specific] selectors‘?
+1 for using the ampersand, it works great with BEM notation.
Very Informative article chris, liked the concept of opt-in typography…
Great article! Another interesting way to develop your CSS is with the attribute module CSS. You can check it out here: http://amcss.github.io/
Sorry but I disagree on certain points. I prefer my HTML to be clean and will add classes when needed, otherwise use the CSS to do the work. The below example is correct in my opinion.
.module > h2 {
/* normal styles /
}
.module .unique {
/ this is how css should cascade */
}
I agree. I write my HTML without a thought of design. THEN I use CSS to style. You can still have a sound CSS code structure without adding classes to everything.
Great stuff Chris !
Hmm, does this not make pre-processors and nesting a bit redundant then?
The other problem with the
.module > h2
example you gave is that it tightly couples the CSS to the flow of the HTML. Why is this bad?Say you wanted to introduce a new element between
.module
andh2
,Now absolutely anything I’ve put in
has now vanished until you rewrite the selector. We used to do this at my company thinking we were cool writing “semantic” HTML and CSS with our fancy new HTML5 selectors, but we quickly ran into this problem.
I really enjoyed the article. I try very hard to stick to a non-specific style of writing css myself but unfortunately, when outside vendor code is thrown in the mix ~ it gets complicated and that’s when things tend to get a little too specific.