Misconceptions about CSS Specificity

Me, at CSS Day 2022, talking about Specificity (and the Cascade)
Me, at CSS Day 2022, talking about Specificity (and the Cascade)

Whenever a post about Specificity in CSS – and by extension the Cascade itself – gets published I get very excited as it’s a core concept of the language that everyone should know. The more articles on this, the better!

However, I also sometimes raise an eyebrow as from time to time I, unfortunately, encounter some parts that are not entirely correct of just outright wrong.

To remove some of the confusion, here’s a (short) list of misconceptions about Specificity in CSS …

~

# Table of Contents

~

# Misconception 1: Specificity is a decimal score

Some, typically older, articles out there express Specificity as a decimal score, or mention that a thing like a class selector “adds 10 points”. This is inaccurate as it would imply that 11 element selectors with their “1 point each” would beat 1 class selector that only has “10 points”.

Instead, Specificity is a triple (or a triad) that has three components: A, B, and C. The values for A, B, and C depend on what type of selector you use.

  • A = id-like specificity
  • B = class-like specificity
  • C = element-like specificity

It is often represented using the (A,B,C) notation. For example: (1,0,2). The alternative A-B-C notation is also commonly used.

🤓 I wrote a JavaScript library that can calculate the specificity of a Selector: @bramus/specificity. It powers this interactive specificity calculator.

Specificities are compared by comparing the three components in order: the specificity with a larger A value is more specific; if the two A values are tied, then the specificity with a larger B value is more specific; if the two B values are also tied, then the specificity with a larger C value is more specific; if all the values are tied, the two specificities are equal.

In code, it looks like this:

const compare = (s1, s2) => {
    if (s1.a === s2.a) {
        if (s1.b === s2.b) {
            return s1.c - s2.c;
        }
        return s1.b - s2.b;
    }
    return s1.a - s2.a;
};

For example, (1,0,0) is a higher specificity than (0,10,3) because the A value in (1,0,0) (which is 1) is greater than the A value from (0,10,3) (which is 0).

Also see this excerpt from my CSS Day 2022 talk about the cascade:

Excerpt from my CSS Day talk on the Cascade, covering how to write and compare Specificity

💡 While you could represent the triad as a decimal by adding enough leading zeroes, it comes with its own set of challenges: the number you end up with is hard to read/parse + you would need to add “enough” zeroes to get a correctly sortable result.

My advice here remains this: don’t.

Where the confusion comes from:

Back in CSS Selectors 3, the spec mentioned that you could concatenate the numbers to get the specificity.

Concatenating the three numbers a-b-c (in a number system with a large base) gives the specificity.

While it is caveated with “in a number system with a large base” the clause got ignored, most likely because the spec showed examples in base 10 – e.g. #s12:not(FOO) /* a=1 b=0 c=1 -> specificity = 101 */.

Almost 15 years later and we are still stuck with it: some writers keep representing Specificity in base 10 because it’s “simpler to explain”. While that might be true, it’s teaching people the wrong thing. Having them unlearn something later on is much much harder to do.

~

# Misconception 2: Using the style attribute adds Specificity

I often read that using the style attribute “adds 1000 points of specificity”. This is not correct as evaluation of the style attribute is an earlier step of the cascade – it has nothing to do with Specificity at all.

The various steps of the cascade (as per CSS Cascade 5), with style attribute highlighted
The various steps of the cascade (as per CSS Cascade 5), with style attribute highlighted

Where the confusion comes from:

Back in the CSS2 days (in 2011) this was actually the case. In that spec, Specificity was quadruple (A,B,C,D), with the style attribute being the A component.

Since CSS3, this is no longer the case, though.

~

# Misconception 3: Using !important adds Specificity

I often read that adding !important to a declaration “adds 10000 points of specificity”. This is not correct as using !important puts the declaration in a different origin. By using !important in your author styles, the declaration moves from the Normal Author Declarations origin to the Important Author Declarations origin.

The various origins (as per CSS Cascade 5) with normal author declarations and important author declarations highlighted
The various origins (as per CSS Cascade 5) with normal author declarations and important author declarations highlighted

Origins and importance is the first criterion of the cascade that is checked. Specificity comes much much later.

Where the confusion comes from:

I couldn’t find any hard traces in the specifications, but my guess this was something someone came up back in the day when the Specificity directly followed the Origins criterion. That simplification did make sense back then but nowadays it no longer does as it skips over three extra criterions of the cascade that sit in between Origins+Importance and Specificity: Context, Element attached styles, and Layers.

~

# Learn more

To learn more about Specificity and the Cascade, I’d recommend you to watch the talk I gave a CSS Day 2022 that digs into all there is to know about it.

On the dedicated post here on bram.us you can also grab the slides.

~

Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Unless noted otherwise, the contents of this post are licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT License

Join the Conversation

2 Comments

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.