What is CSS Specificity?
Specificity is a measure by which browsers decide which CSS property values are the most relevant to an element. Based on that the rules will be applied.
If there are two or more conflicting CSS rules that point to the same element, the browser follows some rules to determine which one is most specific and therefore wins out. Specificity is based on the matching rules which are composed of different sorts of CSS selectors.
Think of specificity as a score/rank that determines which style declarations are ultimately applied to an element.
The universal selector (*) has low specificity, while ID selectors are highly specific!
Note: Specificity is a common reason why your CSS-rules don't apply to some elements, although you think they should.
Specificity only applies when the same element is targeted by multiple declarations.
Specificity Hierarchy
Every selector has its place in the specificity hierarchy.
There are four categories which define the specificity level of a selector:
1. Inline styles – An inline style is attached directly to the element to be styled.
Example:
<p style="color: red;">hello</p>
2. IDs – An ID is a unique identifier for the page elements, such as #div1.
3. Classes, attributes and pseudo-classes – such as :hover, :focus etc.
4. Elements and pseudo-elements – such as h1, div, :before and :after.
Universal selector (*), combinators (+, >, ~, ' ', ||) and negation pseudo-class (:not()) have no effect on specificity. (The selectors declared inside :not() do, however.)
How is specificity calculated?
1000 for style attribute
100 for each ID
10 for each attribute, class or pseudo-class,
1 for each element name or pseudo-element.
To calculate the specificity value (which selector will be applied), we simply look at the selector and add a value of 100 for every id selector, add 10 for every class selector and add 1 for every element selector.
The greater number wins!
Let’s calculate the specificity of the following selectors using this method:
h1.class => 1 class + 1 element = 11
#nav h1[lang="en"] => 1 ID + 1 attribute + 1 element = 111
body #nav .class ul li:first-child => 1 ID + 1 class + 1 pseudo-class + 3 elements
= 123
We can also calculate like this
=> count 1 if the declaration is from is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
=> count the number of ID attributes in the selector (= b)
=> count the number of other attributes and pseudo-classes in the selector (= c)
=> count the number of element names and pseudo-elements in the selector (= d)
The specificity is based only on the form of the selector. In particular, a selector of the form "[id=p33]" is counted as an attribute selector (a=0, b=0, c=1, d=0), even if the id attribute is defined as an "ID" in the source document's DTD.
Concatenating the four numbers a-b-c-d (in a number system with a large base) gives the specificity.
Some examples:
* {} /* a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0 */
li {} /* a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1 */
li:first-line {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
ul li {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
ul ol+li {} /* a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3 */
h1 + *[rel=up]{} /* a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1 */
ul ol li.red {} /* a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3 */
li.red.level {} /* a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1 */
#x34y {} /* a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0 */
style="" /* a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0 */
In the example below, the color of the P element would be green. The declaration in the "style" attribute will override the one in the STYLE element because of cascading rule 3, since it has a higher specificity.
<HEAD>
<STYLE type="text/css">
#x97z { color: red }
</STYLE>
</HEAD>
<BODY>
<P ID=x97z style="color: green">
</BODY>
Some rules
1. If you write down same rule twice then the latest one will apply.
For example, let's say we have one rule in the external style sheet, for e.g.
//style external
p{color:blue}
Also, we have same rule but in the style sheet as well.
//style in the html page
p {
color:red;
}
The second one is closer to the element to be styled, and therefore will be applied.
2. ID selectors have a higher specificity than attribute selectors.
Let's say we have this code in our HTML file.
div#a {background-color: green;}
#a {background-color: yellow;}
div[id=a] {background-color: blue;}
the first rule is more specific than the other two, and will be applied.
3. Contextual selectors are more specific than a single element selector.
The embedded style sheet is closer to the element to be styled.
//external CSS:
#id1 h1 {background-color: red;}
//In HTML file:
#id1 h1 {
background-color: yellow;
}
So, the second rule will be applied.
4. A class selector beats any number of element selectors.
A class selector such as .intro beats h1, p, div, etc.
For example, from the following code, the yellow color will be applied at the end.
.intro {background-color: yellow;}
h1 {background-color: red;}
5. The universal selector and inherited values have a specificity of 0.
*, body * and similar have a zero specificity. Inherited values also have a specificity of 0.
The !important exception
When an important rule is used on a style declaration, this declaration overrides any other declarations.
NOTE: Using !important is bad practice and should be avoided because it makes debugging more difficult by breaking the natural cascading in your stylesheets.
When two conflicting declarations with the !important rule are applied to the same element, the declaration with a greater specificity will be applied.
Always look for a way to use specificity before even considering !important and only use !important on page-specific CSS that overrides foreign CSS (from external libraries, like Bootstrap or normalize.css).
Never use !important when you're writing a plugin/mashup and never use !important on site-wide CSS.
Instead of using !important, consider making better use of the CSS cascade and try to use more specific rules.
The :is() and :not() exceptions
The matches-any pseudo-class :is() and the negation pseudo-class :not() are not considered a pseudo-class in the specificity calculation. But selectors placed into the pseudo-class count as normal selectors when determining the count of selector types.
The :where() exception
The specificity-adjustment pseudo-class :where() always has its specificity replaced with zero.
Tree proximity ignorance
The proximity of an element to other elements that are referenced in a given selector has no impact on specificity. The following style declaration …
body h1 {
color: green;
}
html h1 {
color: purple;
}
… with the following HTML …
<html>
<body>
<h1>Here is a title!</h1>
</body>
</html>
will render as purple title!
This is because the two declarations have equal selector type counts, but the html h1 selector is declared last.
Directly targeted elements vs. inherited styles
Styles for a directly targeted element will always take precedence over inherited styles, regardless of the specificity of the inherited rule. This CSS …
#parent {
color: green;
}
h1 {
color: purple;
}
… with the following HTML …
<html>
<body id="parent">
<h1>Here is a title!</h1>
</body>
</html>
will also render as purple title!
This is because the h1 selector targets the element specifically, but the green selector is only inherited from its parent.
Sources
browsers property rules Specificity