Let's take these three selectors, sorted from the highest specificity to the lowest:
.special-section p { }
.weird-font { }
p { }
Many CSS gurus recommend against nesting like in the first selector .special-section p
, because its specificity is high enough that you can't override it with a simple class like .weird-font
. I would like to find a way to still achieve nesting like in .special-section p
, but without increasing specificity. Something like this:
.weird-font { }
.special-section p /* with hack to decrease specificity */ { }
p { }
It's pretty safe to apply defaults for typography and such document-wide using simple selectors like p
. However, I would like to change those defaults for a particular section, similar to .special-section p
, without having to use hacks to increase the specificity of selectors like .weird-font
. I would rather use a hack to decrease the specificity of .special-section p
than use a hack to increase the specificity of .weird-font
. Is there a way to do this?
These days, in 2018, this is getting close to possible.
First of all, CSS4 will have a way that allows you to create more specific selectors without increasing specificity:
:where(.special-section) p {
color: red;
}
This will set the paragraph color inside .special-section
to red, but with a specificity of 001 (i.e. the same specificity that a plain p
selector would have).
The spec still calls this special pseudo-class :something()
, but chances are it's going to be called :where()
. (Side note: I really want this to be known as the "honey badger selector").
But that's still in the future.
However, there is actually a way to achieve this today, if you don't have to support IE anymore (or are happy with less-than-perfect fallbacks), and that is by using custom properties a.k.a. CSS variables.
So you want this:
.special-section p { color: red; }
.weird-font { color: magenta; }
p { color: green; }
but with the first part having a specificity that's lower than any selector with a class in it. You can do it like this:
.special-section p { --low-specificity-color: red; }
.weird-font { color: magenta; }
p { color: var(--low-specificity-color, green); }
If you run the below snippet in a modern browser, you should notice that the second paragraph is red, because it's in a special section, but the third paragraph is magenta, because it's .weird-font
-- even though .weird-font
has 010 specificity and .special-section p
has 011.
.special-section p { --low-specificity-color: red; }
.weird-font { color: magenta; }
p { color: var(--low-specificity-color, green); }
<p>This is a paragraph.</p>
<section class="special-section">
<p>This is a paragraph inside a special section.</p>
<p class="weird-font">This is a paragraph with a weird font inside a special section.</p>
</section>
<p class="weird-font">This is a paragraph with a weird font.</p>
<div class="weird-font">This is a div with a weird font.</div>
This works because while the --low-specificity-color
is changed with 011 specificity, it is only applied with a 001 specificity.