Skip to content

CSS 2.1 Selector Specificity

I’m probably the 100th person to write about CSS 2.1’s selector specificity, but I’m going to take a stab at it anyway since it seems to be such a stumbling block for so many people.

I’m not writing this to take away from the brilliant explanations of Andy Clarke, Patrick Griffiths, Eric Meyer, or Molly E. Holzschlag, but to merely supplement their posts with, perhaps, another angle. Many people feel the need to re-explain this topic in layman’s terms rather than enduring W3C’s overly technical explanation about specificity.

What is specificity?

To be brief, it’s the applied calculation of the priorities of CSS selectors and how they cascade through a stylesheet. Simply put, selectors with a higher specificity will overrule other selectors in the cascading order.

How it works

There are two ways to determine specificity — the “right” way and the “quick and dirty” way. According to W3C, the specificity is officially calculated using four numbers concatenated, like: a, b, c, d . The “quick and dirty” technique is to assign values to each type of selector and add the values up. For example, general elements have a value of 1, classes have a value of 10, ID’s have a value of 100, and inline styles have a value of 1000. However, this value-based “quick addition” technique is a bit misleading because it presumes that 10 of any value will override the next highest selector. Following that logic if you have 10 ID’s in a style declaration those will override an inline style, because 10 ID’s are worth 100 x 10 which equals 1000 — inline styles being worth 1000. This statement is far from true. However, it can still be used as an easy way to get an idea of the specificity of a particular selector in a declaration; but it should never be fully relied upon.

The W3C states that Concatenating the four numbers a-b-c-d (in a number system with a large base) gives the specificity. This is the correct method to rely on. The reason is because it separates the values into 4 categories: a, b, c, & d. The variable a is reserved for the number of inline styles and has the highest priority. While b is for the number of ID’s, c is for the number of other attributes (including class, but not ID’s) and pseudo-classes, and d is the number of elements. This is the correct order of specificity and pseudo-elements are to be ignored.

Let’s focus on b and c since these are the subjects of confusion. ID selectors (b) are the most valuable asset to CSS, so they are given the second highest priority, next to inline styles (a). ID selectors are written with a # in front of the name given to the ID. So, #content is referencing <div id="content"> which has a value of 100 using the “quick and dirty” method. These selectors, like all selectors, can be used in combination with any other selectors. For instance, #main-area #content would add up to 200.

Class selectors and other attribute selectors are assigned the variable c. These are each given a value of 10 using the “quick and dirty” method. Class selectors are denoted with a dot (.) before the name of the class, like .box. Attribute selectors are declared with the attribute name inside a set of brackets — a[rel="friend"]. It is not necessary to include the value of the attribute. Additionally, the = can be replaced with ~=, *=, ^=, or $= depending on how you’re equating the value. A better concept of these equations can be found on 456 Berea St’s CSS 3 selectors explained post.

Note: Attribute selectors of CSS 2.1 are supported by most modern browsers, and when I say modern browsers I do not mean Internet Explorer 6.

Initially what confused me about attribute selectors and their specificity was whether or not using class= or id= in the attribute selector made it behave like the # (ID) or . (class) of its CSS 2 predecessors. After doing some testing and reading, I found that the attribute selector has the exact same specificity as the class selector (.), regardless of whether it says id= within its little brackets. It will always have a value of 10. Thus, div[id="content"] is less specific than div#content.

Here’s an easy way to visualize all of this (in a poorly misunderstood table element):

exampleinline styleID selectorsclass/attribute selectorselement/type selectors“quick and dirty” value
p em
#whatever p0,1,0,1101
#whatever p.whatever0,1,1,1111
#whatever1 #whatever2 p.whatever0,2,1,1211

If you haven’t seen any specificity charts before I hope my interpretation helped explain it further. Be sure to check out the other explanations too, because Andy Clarke has an awesome example using siths from Star Wars. Maybe I’ll make a diagram of my own someday.

The Atlantic BT Manifesto

The Ultimate Guide To Planning A Complex Web Project