Standardista

CSS3, JavaScript and HTML5 explained

CSS Specificity

Some people are confused by CSS Specificity, especially with all of the (not-so) new CSS3 Selectors. The image below may help make sense of CSS Specificity. Download the PDF

Legend:

  • X-0-0: The number of ID selectors, represented by Sharks
  • 0-Y-0: The number of class selectors, attributes selectors, and pseudo-classes, represented by Fish
  • 0-0-Z: The number of type selectors and pseudo-elements, represented by Plankton a la Spongebob
  • *: The universal selector has no value
  • +, >, ~: combinators, although they allow for more specific targeting of elements, they do not increase specificity values
  • :not(x): The negation selector has no value, but the argument passed increases specificity
CSS Specificity

CSS SpeciFISHity

You can download the PDF of fishy CSS specificity here

Specificity determines which CSS property declaration is applied when two or more declarations apply to the same element with competing property declarations. The most specific selector takes precedence. If specificity is equal, the last declaration in the source order takes precendence.By understanding CSS Specificity, you’ll understand how the browser determines which declaration is more specific and will therefore take precedence. Let’s take this paragraph as an example:

<p class="myClass" id="myDiv">

If you’re familiar with CSS, you’re probably very familiar with the CSS and specificity of these three lines:

#myDiv { color: red;}		1-0-0
.myClass {color: blue;}	0-1-0
p {color: yellow;}			0-0-1

The style block contains three style rules that have a selector that matches the paragraph. If cascade, or source order, were the only concern, the paragraph would be yellow. However, different selectors have different weights. An ID takes precendence over a class selector takes precendence over a type selector. So, the paragraph would be red.

With CSS3 Selectors, order is even more important, as is understanding specificity:

p.myClass { color: red;}			0-1-1
p[id^='my'] {color: blue;}			0-1-1
p:nth-of-type(1n) {color: yellow;}	0-1-1

Had we declared the above three lines instead, source order would be relevant, as class selectors, attribute selectors and structural pseudo-classes all have the same weight in terms of the cascade.

Selector Specificity Weights

  1. !important: Any property declaration with the term !important takes highest precendence, even over inline styles. If !important is declared more than once on conflicting properties targeting the same element, you CSS author be shot, and the other precendence rules are in effect. It’s as if the weight of the selector with the !important declaration were 1-X-A-B-C, for that property only (where A, B and C are the actual values of the parent selector as described below). Because of this, important should not be used, but can be handy in debugging.
  2. style="": If the author includes style attribute on an element, the inline style will take precedence over any styles declared in an external or embedded stylesheet, other than !important declarations. Anyone including style in production should also be shot, Just sayin’. Note that styles added with the JavaScript style (i.e. document.getElementById('myID').style.color = 'purple';) property is in effect creating an inline style ( ... id="myID" style="color: purple"...). The weight of style="" is 1-0-0-0.
  3. id: Among the selectors you’ll actually be including in your stylesheet, ID’s have the highest specificity. The weight of an id selector is 1-0-0 per id.
  4. class/pseudo-class/attributes: As shown in the second code block above, class selectors, attribute selectors and pseudo-classes all have the same weight of 0-1-0.
  5. type: Element type selectors and pseudo-elements, like :first-letter or :after have the lowest value in terms of specificity with 0-0-1 per element.

If more than one selector have the same specificity, then adhere to the cascade: the last declared rule takes precedence.

Calculating Specificity

To calculate the specificity of a declaration, count the element types, class/pseudo-class/attributes and ids in your declaration. Add each group up separately.

Using the expression X-Y-Z

  • To calculate X, count the number of ID attributes in the selector.
  • To calculate Y, count the number of classes, attributes selectors and pseudo-classes in the selector. Do not count :not, but do count the selectors passed as an argument in the :not(X-Y-Z) selector.
  • To calculate Z, count the number of element names and pseudo-elements in the selector.

For example, if you have 1 id, 12 class/pseudo-class/attributes, and 5 types, you are over declaring your selectors, but the value would be 1-12-5. Note that the final value of X-Y-Z is not a number, but a matrix. No matter how many class, attribute and pseudoclass selectors you have, a single ID will overpower them. If you use the speciFISHity example, no quantity of plankton (elements) will ever beat out a fish (class). No fish will beat out a shark (id). Not Shark can win against an oil tanker (inline), and even an oil tanker will succumb to a nuclear blast. Yeah, I got political on you!

Things that are less obvious:

  • The * selector, or global selector, has no value. *.myClass will be overwritten by p.myClass, even if it is last in the cascade.

  • Combinators, like ~, >, and + have no value in the weighting of selectors. Yes, they help you to be more specific in what you are targeting, but can be overwritten by another selector with the same weight.

    ul > li {color: red;} 0-0-2
    ul  li {color: blue;} 0-0-2

    In the above example, your list items will be blue not read, as they both have the exact same value, and the blue is declared later.

  • :not has no value, but the selectors without the negation selector do

    li.myClass {color: red;} 0-1-1
    li:not([title]) {color: blue;} 0-1-1

    The above both have the same weight because we count the attribute selector and not the :not in the blue declaration.

  • Specifity is not inherited. If you declare 27 values on a parent of a paragraph, and even add !important, but declare the paragraph separately, the property declared on the element will be applied. Inheritance does not trump such declarations.

    &ltldiv id="x" class="y"><p>Hi&lt/p><div>
    div#y.y {color:red;} 1-1-0
    p {color: blue;} 0-0-1

    The paragraph will be blue not red, as although the first declaration is more specific, and colors are inherited, the second declaration is actually applied to the element, whereas the first is applied to the parent. The color is only inherited if not specifically declared on the descendant. And, in this case, it is declared.

7 Responses to “CSS Specificity”

  1. Gaurav says:

    Earlier, i watched the Andy’s version (stuffandnonsense.co.uk)
    this is also good with TEETH


    ________ __
    | * * |\ / /
    |WWWW| \/ <
    |WWWW| /\___\

  2. Virginia says:

    Love the chart – very clever illustrations. Thanks for making it available for download.

  3. [...] Standardista vient de publier une infographie assez parlante, pour mieux comprendre le poids des sélecteurs. Avec le lot de nouveautés apportés par CSS3, ce visuel assez réussi (surtout si on aime les sushis) et disponible en téléchargement devrait en ravir certains. [...]

  4. [...] very often in the work I’m doing right now and sometimes it can get confusing! Head over to Standardista for a very clever graphic using fishies (as I like to call them) and helpful [...]

  5. Julia says:

    Thank you for such crystal clear explanation (may I add that the illustration is missed Spongebob from the Krusty Krab.. the person who does the conversion ))

  6. Chris Mcnally says:

    excellent tutorial! thank you. I like to call the plankton “krill”. also you have a typo which when you fix you might as well delete or edit my comment

    s/read/red

    In the above example, your list items will be blue not read, as they both have the exact same value, and the blue is declared later.

Leave a Reply