Skip to content
Article

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
style=""1,0,0,01000
p0,0,0,11
p em
0,0,0,22
p.whatever0,0,1,111
p[id="whatever"]0,0,1,111
p[href="whatever"]0,0,1,111
#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

Insights

Atlantic BT's Insights

We’re sharing the latest concepts in tech, design, and software development. Learn more about our findings.

Questions & Answers

Are there differences in application architecture that are important for the cloud?
It is important to build applications and workloads specifically for the cloud. You will want to carefully consider what services the cloud provider of your choice has to offer and how your application leverages those services.
Learn More about Are there differences in application architecture that are important for the cloud?
Are there any drawbacks to cloud hosting?
Yes, there will always be some risks associated with any hosting option. You are relying on the resiliency and engineering of infrastructure that has scaled at an astounding rate.
Learn More about Are there any drawbacks to cloud hosting?
What’s the benefit of hosting in the cloud vs. traditional options?
Reasons not to host in the cloud are few and far between. If you don't host in the cloud, you will spend more in both CapEx and OpEx to manage your applications or websites in a traditional environment.
Learn More about What’s the benefit of hosting in the cloud vs. traditional options?
How can I improve the performance of my application?
There are several primary reasons that applications perform poorly, and in some cases it’s a combination of several. 1) Data latency: If your application is making calls to a data source (whether it’s an API or a direct call) and there is latency at the data provider, your application performance will suffer.
Learn More about How can I improve the performance of my application?
Should I move my application to the cloud?
The answer is ‘probably yes’. There aren’t many reasons for an application to be hosted elsewhere, aside from occasional compliance standards, or requirements to integrate with local services that would require large amounts of data to move from on-premise to cloud.
Learn More about Should I move my application to the cloud?
Where should my application be hosted?

There are many different options for hosting, but most applications would do well with one of the cloud providers -- Amazon Web Services, Google Cloud Platform, Microsoft Azure.

Learn More about Where should my application be hosted?