The following is a guest adventure by Francisco Dias from HubSpot. I saw Francisco and Cris Necochea give this as a quick, fun presentation at the Show & Tell at CSS Dev Conf this year. He graciously agreed to prepare it for a blog post!
19 ways to override a background color
Starting with pretty much the lowest specificity selector:
div {
background: black;
}
There are an awful lot of ways to one-up the existing specificity without repeating the same trick.
Click through each step to see the spies force their color (black or white) on top of the previous color. When the specificity one-upping stops, there are still more tricks up their sleeve!
(The Spy shape is created from a clip-path
on the div
in the demo to make it more fun and Spy-vs-Spy like. If the browser you’re currently in doesn’t support clip-path, you’ll just see white or black boxes.)
See the Pen Spy Vs Spy by Francisco Dias (@FranDias) on CodePen.
What the heck is going on here? The text inside the demo Pen above has a bit more information on each step, but just as a quick overview, here are the stages:
Step 1: Element Selector
0, 0, 0, 1
div {
background: black;
}
Step 2: Two Element Selectors
0, 0, 0, 2
body div {
background: white;
}
Step 3: Three Element Selectors
0, 0, 0, 3
html body div {
background: black;
}
Step 4: Class Selector
0, 0, 1, 0
.spy {
background: white;
}
Step 5: Class + Element Selector
0, 0, 1, 1
div.spy {
background: black;
}
Step 6: Element + Class + Pseudo-Class Selector
0, 0, 2, 1
div.spy:only-of-type {
background: white;
}
Step 7: Stacked Classes
0, 0, ∞, 0
.spy.spy.spy.spy.spy.spy.spy.spy.spy {
background: black;
}
Step 8: ID Selector
0, 1, 0, 0
#spy {
background: white;
}
Step 9: ID + Attribute Selector
0, 1, 1, 0
#spy[class^="s"] {
background: black;
}
Step 10: Combining Many Above…
0, 1, 3, 3
html body div#spy[class="spy"]:first-of-type.spy {
background: white;
}
Step 11: Inline Style
1, 0, 0, 0
<div class="spy" id="spy" style="background: black;"></div>
Step 12: !important
Kind of like [1, 0, 0, 0] on a per-property basis (can override an inline style).
div {
background: white !important;
}
Step 13: !important on inline style
Kind of like [∞, 0, 0, 0] on a per property basis, which no CSS can override.
<div class="spy" id="spy" style="background: black !important;"></div>
Step 14: box-shadow trickery
Some properties paint on top of others. box-shadow
paints on top of background.
div {
box-shadow: inset 0 9001rem 0 white;
}
Step 15: Invert Filter
div {
-webkit-filter: invert(1);
filter: invert(1);
}
Step 16: Pseudo Element Overlay
div::after {
content: "";
height: 9001px;
width: 9001px;
background: black;
top: 0;
left: 0;
position: absolute;
}
Step 17: !important again
All the specificity battles could be fought again, including the per-property battle using !important;
, so let’s end that here.
div:after {
background: white !important;
}
Step 18: @keyframes trickery
!important
isn’t animateable, so the animation can override it.
@keyframes white {
to {
background: black;
}
}
div:after {
animation: white 1s linear;
animation-play-state: paused;
animation-delay: -1s;
animation-fill-mode: forwards;
}
Step 19: Coloring the Content
Putting a huge block character over everything flips the color again!
div:after {
content: "█";
line-height: 0;
color: white;
font-size: 9001px;
}
A gif of the demo in large-screen-Chrome:

I was fortunate enough to see this live at that show and tell. Cool presentation. Well done fellas
Double thanks, for the encouragement during the presentation and now.
Now I can’t get the song “50 Ways to Leave Your Lover” out of my head . . .
We need something like !superimportant that will simply overwrite all that crappy css (importants everywhere, today I saw important on the selector ‘a img’ that ruins my whole Joomla portal) of third party components that were written by junior developers. Yeh why not!
I don’t think that would be good :)
The problem is that once those junior developers learn of this new specificity, we would need to add
!superduperimportant
:)I agree with Brad and Jeffrey—
What we need is better awareness of how to encapsulate your features responsibly. Jeffery Sweeny put it very well, if we had something more extreme than
!important
they probably would have used that.There are cases where an
!important
modifier with a consciously specific selector or utility class with just one function like.uppercase { text-transform: uppercase;}
can be useful and even help scale a project. Unfortunately,!important
seems to be used more out of frustration rather than as a conscious tool.I think that a more effective thing to have would be a way to ignore !important and revert to standard specificity. That way, instead of launching into a pushy devs’ arms race for higher trump cards, it would be a way for people who actually understood CSS to untangle the mess left by others.
So we have the specificity that we understand and so ‘div > p’ is higher than ‘p’ and wins. Let just simplify and make it !1, !2, !3, !4… up to infinity?, 100? Much simpler ;) If you see a junior using !100 then is pure evil :D
Half joking, half seriously, ye why not – discuss.
P.S. anyway I think it is better learn the specificity instead of adding more stuff at the end of single css rules.
Well, from the very beginning, CSS was designed to have individual local user css that overrides server-sent author css (but everybody hates that and pretends it doesn’t exist), so it would be conceivable to have a distinction between cross-site CSS and own-site CSS. (Won’t help here, though, since !important already trumps user css.)
Have to agree with the other comments. Also – you might want to reconsider using such an extension, at all (of course, the devs could be super proficient at PHP/JS and just new to CSS …).
!unimportant would be awesome
Example
sorry… typo in the example, should be !unimportant
doh!
The
!important
rule should be treated more like a debugging tool. Just like debug messages, it shouldn’t be used in production code. The last thing we need is another layer of specificity like !superimportant. The one we have now causes too many problems.I’d even be in favor of a flag / rule / directive / assertion that we could put in our code that just disables it.
“They had atomic bombs, so we built hydrogen bombs” isn’t exactly the best software architecture strategy. ;)
That must be the most creative and informative demonstration of CSS specificity I’ve ever seen. I saw so many clever techniques I haven’t seen or thought of before, and yet, I suspect there’s dozens more that have been left out.
Wow thank you for that comment that’s a huge compliment. There’s two tricks in the source that were commented out because they don’t work with
clip-path
and you can also chain ID’s#spy#spy#spy
. Other than that I didn’t want to get into!important
on animations or using minutely more specific selectors to avoid feeling pedantic. Thanks again!#19 didn’t show for me. I just see the hot pink body. Still an awesome presentation, though. I’m using Chrome Version 48.0.2564.71 beta-m (64-bit).
My favorite technique for dealing with specificity issues:
Thanks for the bug report & compliment. I’ll see what I can do.
I was expecting to see the inline style override trick here but since I didn’t; here it is. Let’s say you have a div with an online style applied (probably by JavaScript), then you can do this to override the inline style from the internal/external CSS.
You’re just using the
!important
rule to override inline CSS as we saw in step 12.I think it’s important to note that changing the appearance of an element using Javascript by modifying the style property isn’t the same as an inline style. It just has the same specificity.
There is something interesting here, though. I expected your CSS to target only elements that actually have a
style
property set in the HTML, but I was wrong. Apparently, it also targets elements that have had the style property set in the DOM using Javascript.Lowest is *.
The universal selector doesn’t carry any specificity (neither does !important).
Your right (unless you count browser default styles). It just wasn’t included because I couldn’t put it naked. Thanks for the comment.
And thanks for the article – the trickery from step 14 onward is interesting (if hacky).
This is about the background color, but if you were trying to change the text color one of the trickiest beasts I’ve ever seen is -webkit-text-fill-color. Really, that one has driven me mad once, when for a whole hour I couldn’t understand why not even !important was working…