How Does the CSS Specificity Work

How does the CSS specificity work?

The first says that any an item with class c inside of any item with of class a will be colored red.

.a .c {
color: red;
}

The second says that any an item with class c inside of any item of class b will be colored green. It takes precedence over the first rule as it is just as deep as the first rule, but defined after that rule.

.b .c {
color: green;
}

This says that any item with the class c should be blue. But since it is not as descriptive as the rules above, it does not take precedence. If you have an item with class c that is not nested inside a class a or b, then this rule will take effect.

.c {
color: blue;
}

So there are two rules to remember:

  • The more specific rules get higher precedence
  • The later defined rules get higher precedence than their just-as-specific counterparts.

CSS specificity and !important

Styles for a directly targeted element will always take precedence over inherited styles, regardless of the specificity of the inherited rule.

-- Specificity: Directly targeted elements vs. inherited styles


Note: the addition of the new contrived ruleset in Demo:

div.outer.outer.outer>div.inner1>div.inner2.inner2>aside.inner3 {
color: blue !important
}

It has an incredibly ridiculously unnecessarily huge specificity score of 0,0,7,4 and !important as well. CSS reads from right to left:

  1. Find an <aside> tag with the class of .inner3
  2. It must have a parent <div> that has the class of .inner2.
  3. Also that <div class="inner2">must have a parent <div> with a class of .inner1.
  4. And it's imperative that <div class="inner1"> have a parent <div> with the class of .outer.

All of these specific rules of the selector must be met just so a deeply nested <aside> tag gets its style. Any descendant elements of .inner3 will inherit color: blue property and value, but it is easily overridden by the likes of i.inner2 with color:red.

   <div class="inner3">
<p>This deeply nested text has <i class='inner2'>crazy specificity but this text is red.</i>
...
</p>
</div>

Note: the new ruleset at the bottom of CSS box:

  div {
color: black !important
}

Now this selector is specific to all divs so here is how !important has just been assigned a selector with a far reaching scope. This is probably more like the behavior you were expecting.


BTW, you probably noticed the duplicate classes:

  .outer.outer.outer

That is called selector chaining which will increase a selector's specificity score. See Online Specificity Calculator.


Demo


div.outer.outer.outer>div.inner1>div.inner2.inner2>aside.inner3 {  color: blue !important}
.outer .inner1 { color: green !important;}
.outer .inner1 .inner2 { color: red;}
div { color:black !important;}
<head>  <link href="css/style.css" rel="stylesheet">  <link href="css/style1.css" rel="stylesheet"></head>
<body> <div class="outer"> <div class="inner1"> This text will be green... <div class="inner2"> <p>Voluptate labore cupidatat an enim quamquam ut anim malis, varias id sed veniam quibusdam, singulis aliqua ut singulis domesticarum, id aliqua illum o officia, et ab domesticarum, irure e excepteur o eram nam appellat coniunctione do commodo.. </p>
<aside class='inner3'> <p>This deeply nested text has <i class='inner1'>crazy specificity</i>, yet it only applies to it and its descendants with no specific <b class='inner2'>`color` property</b>.</p> </aside> </div> ...and this text will be green as well. </div> </div>

How are the points in CSS specificity calculated

Pekka's answer is practically correct, and probably the best way to think about the issue.

However, as many have already pointed out, the W3C CSS recommendation states that "Concatenating the three numbers a-b-c (in a number system with a large base) gives the specificity." So the geek in me just had to figure out just how large this base is.

It turns out that the "very large base" employed (at least by the 4 most commonly-used browsers*) to implement this standard algorithm is 256 or 28.

What this means is that a style specified with 0 ids and 256 class-names will over-ride a style specified with just 1 id. I tested this out with some fiddles:

  • 255 classes are not enough to override 1 id

  • ...but 256 classes are enough to override 1 id

  • ...and 256 tag-names are enough to override 1 class-name

  • ...but, alas 256 ids are not enough to override 1 inline style (Updated 2012/8/15 -- you'll have to use !important)

So there is, effectively, a "point system," but it's not base 10. It's base 256. Here's how it works:

(28)2 or 65536, times the number of ids in the selector

  • (28)1 or 256, times the number of class-names in the selector
  • (28)0 or 1, times the number of tag-names in the selector

This isn't very practical for back-of-the-envelop exercises to communicate the concept.

That's probably why articles on the topic have been using base 10.

***** [Opera uses 216 (see karlcow’s comment). Some other selector engines use infinity — effectively no points system (see Simon Sapin’s comment).]

Update, July 2014:

As Blazemonger pointed out earlier in the year, webkit browsers (Chrome, Safari) now appear to use a higher base than 256. Perhaps 216, like Opera? IE and Firefox still use 256.

Update, March 2021:

Firefox no longer uses 256 as a base.

How does specificity work with inherited styles?

From the MDN page on Specifity

Styles for a directly targeted element will always take precedence over inherited styles, regardless of the specificity of the inherited rule.

https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity

Hence p will override .container no matter what. The inherited style from .container is overwritten

Understanding specificity: achieving desired selector outcomes without using !important

A class has a specificity of 10. An element has a specificity of 1.

Therefore, in the first instance:

  • the .main li a selector has a specificity of 12.
  • the .active a selector has a specificity of 11

Because they both target the same element, and the former has a higher specificity, the latter loses the battle to style the element.

In the second instance:

  • the .primary p selector has a specificity of 11.
  • the .copyright selector has a specificity of 10.

Again, because they both target the same element, and the former has a higher specificity, the latter loses the battle to style the element.

The !important annotation trumps all specificity. Hence, with that applied, .active a and .copyright re-take the elements.

If you want to remove !important, which would be the right thing to do as it's not necessary here, you can instead boost the specificity of the selectors.

An ID has a specificity of 100. So that can quickly move a selector up in priority.

Here are some examples:

.main li a      { color: #7ab2c1; }  /* previous winner; specificity 12 */.main .active a { color: #ff0000; }  /* added class selector; specificity now 21 */.primary p      { font-size: 12px; } /* previous winner; specificity 11 */#copyright      { font-size: 8px;} /* switched to ID selector; specificity now 100 */
<nav class="main">  <ul class="group">    <li class="active"><a href="#">Home</a></li>    <li><a href="#">About</a></li>    <li><a href="#">Contact</a></li>  </ul></nav><footer class="primary">  <p><a href="#">Sign up</a> for our newsletter, it's a racket!</p>  <p id="copyright">Copyright © Sven's Snowshoe Emporium.                    All Rights Reserved.</p></footer>

Relationship between !important and CSS specificity

Specificity in CSS only concerns selectors, not their associated declarations. !important applies to a declaration, so it alone plays no role in specificity.

However, !important influences the cascade, which is the overall calculation of styles for a certain element when more than one of the same property declaration applies to it. Or, as Christopher Altman succinctly describes:

  1. !important is a spades card. It trumps all specificity points.

But not only that: because it influences the cascade overall, if you have more than one !important selector with a rule containing an !important declaration matching the same element then selector specificity will continue to apply. Again, this is simply due to having more than one rule applying to the same element.

In other words, for two rules with unequal selectors in the same stylesheet (e.g. same user stylesheet, same internal author stylesheet, or same external author stylesheet), the rules with the most specific selector apply. If there are any !important styles, the one in the rule with the most specific selector wins. Finally, since you can only have something that's either important or not, that's quite as far as you can go in influencing the cascade.

Here's an illustration of the various uses of !important and how they're applied:

  • The !important declaration always overrides the one without it (except in IE6 and older):

    /* In a <style> element */
    #id {
    color: red !important;
    color: blue;
    }
  • If there is more than one !important declaration in a rule with the same level of specificity, the later-declared one wins:

    /* In a <style> element */
    #id {
    color: red !important;
    color: blue !important;
    }
  • If you declare the same rule and the same property in two different places, !important follows the cascading order if both declarations are important:

    /* In an externally-linked stylesheet */
    #id {
    color: red !important;
    }

    /* In a <style> element appearing after the external stylesheet */
    #id {
    color: blue !important; /* This one wins */
    }
  • For the following HTML:

    <span id="id" class="class">Text</span>

    If you have two different rules and one !important:

    #id {
    color: red;
    }

    .class {
    color: blue !important;
    }

    That !important always wins.

    But when you have more than one !important:

    #id {
    color: red !important;
    }

    .class {
    color: blue !important;
    }

    The #id rule has a more specific selector, so that one wins.

CSS specificity testing

The method I settled with is to use getComputedStyle to get the style with "highest priority". In the css I add a "tag" to the content property. In jasmine I then check if the desired tag is the computedStyle. (I will extend this in scss so that the content property is set by a mixin if test mode is used and not set in production.) This only makes a unit test for the class of highest priority, but not for the second highest etc.

Below is a tests to illustrate the example (only the first and last should pass).

// specs codedescribe("CSS", function() {  it("Div element of class test should be handled by .test", () => {    const testdiv = document.getElementById("testdiv")    m = window.getComputedStyle(testdiv).getPropertyValue("content");        expect(m).toEqual('".test"');  });
it("Div element of class test should be handled by div", () => { const testdiv = document.getElementById("testdiv") m = window.getComputedStyle(testdiv).getPropertyValue("content"); expect(m).toEqual('"div"'); });
it("Div element should be handled by .test", () => { const testdiv = document.getElementById("testdiv2") m = window.getComputedStyle(testdiv).getPropertyValue("content"); expect(m).toEqual('".test"'); });
it("Div element of class test should be handled by div", () => { const testdiv = document.getElementById("testdiv2") m = window.getComputedStyle(testdiv).getPropertyValue("content"); expect(m).toEqual('"div"'); });
});

// load jasmine htmlReporter(function() { var env = jasmine.getEnv(); env.addReporter(new jasmine.HtmlReporter()); env.execute();}());
.test {    content: '.test';}
div { content: 'div';}
<script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script><script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script><link href="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" rel="stylesheet"/><div class="test" id="testdiv">TestDiv</div><div id="testdiv2">TestDiv</div>

How does CSS specificity decide which styles to apply?

It's based on IDs, classes and tags. IDs have the highest specificity, then classes then tags, so:

.item a     == 0 1 1      0 (id) 1 (class=item) 1 (tag=a)
.special == 0 1 0
#foo == 1 0 0
#foo .bar a == 1 1 1
#foo #bar == 2 0 0

whichever has the most wins :) If it's a tie, whichever one comes last in the document wins. Note that 1 0 0 beats 0 1000 1000

If you want .special to apply, make it more specific: .item a.special

Specificity rules for comma delineated lists

Remember that CSS is cascading - meaning the style that is referenced FURTHER down a CSS file will take precedence assuming the selector is the same:

header {  background-color: red;}p, span, header {  background-color: yellow;}
<header>  HEADER</header>

Why does the :link pseudo class break expected CSS specificity rules?

The specification you link to states that a pseudo-class (:link in this case) has higher specificity than an element name. To be precise, using the a-b-c-d format, your three selectors come out as:

a-b-c-d
0 0 1 1
0 0 0 3
0 0 1 3

Your confusion possible comes from your use of the term "pseudo selector" which fails to recognise the distinction between pseudo-classes such as :link and pseudo-elements such as :first-line.



Related Topics



Leave a reply



Submit