The CSS Podcast - 003: Specificity
Suppose that you're working with the following HTML and CSS:
<button class="branding">Hello, Specificity!</button>
button {
color: red;
}
.branding {
color: blue;
}
There's two competing rules here. One will color the button red and the other will color it blue. Which rule gets applied to the element? Understanding the CSS specification's algorithm about specificity is the key to understanding how CSS decides between competing rules.
Specificity is one of the four distinct stages of the cascade, which was covered in the last module, on the cascade.
Specificity scoring
Each selector rule gets a scoring. You can think of specificity as a total score and each selector type earns points towards that score. The selector with the highest score wins.
With specificity in a real project, the balancing act is making sure the CSS rules you expect to apply, actually do apply, while generally keeping scores low to prevent complexity. The score should only be as high as we need it to be, rather than aiming for the highest score possible. In the future, some genuinely more important CSS might need to be applied. If you go for the highest score, you'll make that job hard.
Scoring each selector type
Each selector type earns points. You add all of these points up to calculate a selector's overall specificity.
Universal selector
A universal selector (*
)
has no specificity and gets 0 points.
This means that any rule with 1 or more points will override it
* {
color: red;
}
Element or pseudo-element selector
An element (type) or pseudo-element selector gets 1 point of specificity .
Type selector
div {
color: red;
}
Pseudo-element selector
::selection {
color: red;
}
Class, pseudo-class, or attribute selector
A class, pseudo-class or attribute selector gets 10 points of specificity.
Class selector
.my-class {
color: red;
}
Pseudo-class selector
:hover {
color: red;
}
Attribute selector
[href='#'] {
color: red;
}
The :not()
pseudo-class itself adds nothing to the specificity calculation.
However, the selectors passed in as arguments do get added to the specificity calculation.
div:not(.my-class) {
color: red;
}
This sample would have 11 points of specificity
because it has one type selector (div
) and one class inside the :not()
.
ID selector
An ID
selector gets 100 points of specificity,
as long as you use an ID selector (#myID
) and not an attribute selector ([id="myID"]
).
#myID {
color: red;
}
Inline style attribute
CSS applied directly to the style
attribute of the HTML element,
gets a specificity score of 1,000 points.
This means that in order to override it in CSS,
you have to write an extremely specific selector.
<div style="color: red"></div>
!important
rule
Lastly, an !important
at the end of a CSS value gets a specificity score of 10,000 points.
This is the highest specificity that one individual item can get.
An !important
rule is applied to a CSS property,
so everything in the overall rule (selector and properties) does not get the same specificity score.
.my-class {
color: red !important; /* 10,000 points */
background: white; /* 10 points */
}
Check your understanding
Test your knowledge of specificity scoring
What is the specificity score of a[href="#"]
?
a
is worth 1 point, but the [href="#"]
is worth 10 points.a
is worth 1 point and the [href="#"]
is worth 10 points, making a total score of 11 points.Specificity in context
The specificity of each selector that matches an element is added together. Consider this example HTML:
<a class="my-class another-class" href="#">A link</a>
This link has two classes on it. Add the following CSS, and it gets 1 point of specificity:
a {
color: red;
}
Reference one of the classes in this rule, it now has 11 points of specificity:
a.my-class {
color: green;
}
Add the other class to the selector, it now has 21 points of specificity:
a.my-class.another-class {
color: rebeccapurple;
}
Add the href
attribute to the selector,
it now has 31 points of specificity:
a.my-class.another-class[href] {
color: goldenrod;
}
Finally,add a :hover
pseudo-class to all of that,
the selector ends up with 41 points of specificity:
a.my-class.another-class[href]:hover {
color: lightgrey;
}
Check your understanding
Test your knowledge of specificity scoring
Which of the following selectors is worth 21 points?
article > section
article.card.dark
article:hover a[href]
Visualizing specificity
In diagrams and specificity calculators, the specificity is often visualized like this:
The left group is id
selectors.
The second group is class, attribute, and pseudo-class selectors.
The final group is element and pseudo-element selectors.
For reference, the following selector is 0-4-1
:
a.my-class.another-class[href]:hover {
color: lightgrey;
}
Check your understanding
Test your knowledge of specificity visualizing
Which of the following selectors is 1-2-1
?
section#specialty.dark
1-1-1
.#specialty:hover li.dark
[data-state-rad].dark#specialty:hover
1-3-0
.li#specialty section.dark
1-1-2
.Pragmatically increasing specificity
Let's say we have some CSS that looks like this:
.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
With HTML that looks like this:
<button class="my-button" onclick="alert('hello')">Click me</button>
The button has a grey background,
because the second selector earns 11 points of specificity (0-1-1
).
This is because it has one type selector (button
),
which is 1 point and an attribute selector ([onclick]
), which is 10 points.
The previous rule—.my-button
—gets 10 points (0-1-0
),
because it has one class selector.
If you want to give this rule a boost, repeat the class selector like this:
.my-button.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
Now, the button will have a blue background,
because the new selector gets a specificity score of 20 points (0-2-0
).
A matching specificity score sees the newest instance win
Let's stay with the button example for now and switch the CSS around to this:
.my-button {
background: blue;
}
[onclick] {
background: grey;
}
The button has a grey background,
because both selectors have an identical specificity score (0-1-0
).
If you switch the rules in the source order, the button would then be blue.
[onclick] {
background: grey;
}
.my-button {
background: blue;
}
This is the only instance where newer CSS wins. To do so it must match the specificity of another selector that targets the same element.