Each individual CSS Selector has its own specificity value. Every selector in a sequence increases the sequence's overall specificity. Selectors fall into one of three different specificity groups: A, B and c. When multiple selector sequences select a given element, the browser uses the styles applied by the sequence with the highest overall specificity.
Group | Comprised of | Examples |
---|---|---|
A | id selectors | #foo |
B | class selectors attribute selectors pseudo-classes | .bar [title] , [colspan="2"] :hover , :nth-child(2) |
c | type selectors pseudo-elements | div , li ::before , ::first-letter |
Group A is the most specific, followed by Group B, then finally Group c.
The universal selector (*
) and combinators (like >
and ~
) have no specificity.
#foo #baz {} /* a=2, b=0, c=0 */
#foo.bar {} /* a=1, b=1, c=0 */
#foo {} /* a=1, b=0, c=0 */
.bar:hover {} /* a=0, b=2, c=0 */
div.bar {} /* a=0, b=1, c=1 */
:hover {} /* a=0, b=1, c=0 */
[title] {} /* a=0, b=1, c=0 */
.bar {} /* a=0, b=1, c=0 */
div ul + li {} /* a=0, b=0, c=3 */
p::after {} /* a=0, b=0, c=2 */
*::before {} /* a=0, b=0, c=1 */
::before {} /* a=0, b=0, c=1 */
div {} /* a=0, b=0, c=1 */
* {} /* a=0, b=0, c=0 */
Imagine the following CSS implementation:
#foo {
color: blue;
}
.bar {
color: red;
background: black;
}
Here we have an ID selector which declares color
as blue, and a class selector which declares color
as red and background
as black.
An element with an ID of #foo
and a class of .bar
will be selected by both declarations. ID selectors have a Group A specificity and class selectors have a Group B specificity. An ID selector outweighs any number of class selectors. Because of this, color:blue;
from the #foo
selector and the background:black;
from the .bar
selector will be applied to the element. The higher specificity of the ID selector will cause the browser to ignore the .bar
selector's color
declaration.
Now imagine a different CSS implementation:
.bar {
color: red;
background: black;
}
.baz {
background: white;
}
Here we have two class selectors; one of which declares color
as red and background
as black, and the other declares background
as white.
An element with both the .bar
and .baz
classes will be affected by both of these declarations, however the problem we have now is that both .bar
and .baz
have an identical Group B specificity. The cascading nature of CSS resolves this for us: as .baz
is defined after .bar
, our element ends up with the red color
from .bar
but the white background
from .baz
.
The last snippet from Example 2 above can be manipulated to ensure our .bar
class selector's color
declaration is used instead of that of the .baz
class selector.
.bar {} /* a=0, b=1, c=0 */
.baz {} /* a=0, b=1, c=0 */
The most common way to achieve this would be to find out what other selectors can be applied to the .bar
selector sequence. For example, if the .bar
class was only ever applied to span
elements, we could modify the .bar
selector to span.bar
. This would give it a new Group C specificity, which would override the .baz
selector's lack thereof:
span.bar {} /* a=0, b=1, c=1 */
.baz {} /* a=0, b=1, c=0 */
However it may not always possible to find another common selector which is shared between any element which uses the .bar
class. Because of this, CSS allows us to duplicate selectors to increase specificity. Instead of just .bar
, we can use .bar.bar
instead (See The grammar of Selectors, W3C Recommendation). This still selects any element with a class of .bar
, but now has double the Group B specificity:
.bar.bar {} /* a=0, b=2, c=0 */
.baz {} /* a=0, b=1, c=0 */
!important
and inline style declarationsThe !important
flag on a style declaration and styles declared by the HTML style
attribute are considered to have a greater specificity than any selector. If these exist, the style declaration they affect will overrule other declarations regardless of their specificity. That is, unless you have more than one declaration that contains an !important
flag for the same property that apply to the same element. Then, normal specificity rules will apply to those properties in reference to each other.
Because they completely override specificity, the use of !important
is frowned upon in most use cases. One should use it as little as possible. To keep CSS code efficient and maintainable in the long run, it's almost always better to increase the specificity of the surrounding selector than to use !important
.
One of those rare exceptions where !important
is not frowned upon, is when implementing generic helper classes like a .hidden
or .background-yellow
class that are supposed to always override one or more properties wherever they are encountered. And even then, you need to know what you're doing. The last thing you want, when writing maintainable CSS, is to have !important
flags throughout your CSS.
A common misconception about CSS specificity is that the Group A, B and c values should be combined with each other (a=1, b=5, c=1
=> 151). This is not the case. If this were the case, having 20 of a Group B or c selector would be enough to override a single Group A or B selector respectively. The three groups should be regarded as individual levels of specificity. Specificity cannot be represented by a single value.
When creating your CSS style sheet, you should maintain the lowest specificity as possible. If you need to make the specificity a little higher to overwrite another method, make it higher but as low as possible to make it higher. You shouldn't need to have a selector like this:
body.page header.container nav div#main-nav li a {}
This makes future changes harder and pollutes that css page.
You can calculate the specificity of your selector here