DEV Community

Habdul Hazeez
Habdul Hazeez

Posted on • Edited on

CSS Specificity

CSS specificity is one of the mechanism used by the browser to resolve conflicts in your CSS rules. Now you might be thinking: conflict? What conflict?

Given the code snippet below, which particular CSS rule do you think will get applied to the HTML paragraph?

<div>
 <p id="paragraph">Hello world, welcome to frontend zero to hero</p>
</div>
Enter fullscreen mode Exit fullscreen mode
p {
  font-size: 120%; /* option one */
}

div p {
  font-size: 0.5em; /* option two */
}

#paragraph {
  font-size: 10px; /* option three */
}
Enter fullscreen mode Exit fullscreen mode

Taking a closer look, you'll notice that we are trying to change the font-size of the paragraph with three different rules in our CSS. That's the conflict I was talking about. But which rule will the browser use? Take a guess.

Option three will win. Why option three? When you give such rules, the browser will use one of its a mechanism in resolving conflicts in CSS rules โ€” specificity. In this case, the browser will use the rule declared with the id selector to style the paragraph. How could this be? To answer this question, let's find out how the browser calculates a selector specificity.

CALCULATING A SELECTOR SPECIFICITY

From the CSS Specification:

A selector's specificity is calculated as follows:

  • count 1, if the declaration is from, is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
  • count the number of ID attributes in the selector (= b)
  • count the number of other attributes and pseudo-classes in the selector (= c)
  • count the number of element names and pseudo-elements in the selector (= d)

At first glance this might be confusing, let's explain each step of the algorithm.

count 1 if the declaration is from is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules.

This translates to: When you apply some styling to an HTML Element using the style attribute it will have a value of 1 and all property declaration in this style attribute will be used by the browser even if you declare the same set of properties with other selectors (id,class or type selectors).

Let's use our previous example with a slight modification. Save the HTML code in a file with the .html extension and the CSS with a .css extension, and make sure the CSS is linked with the HTML (if you don't know how to do this, please check the previous article CSS units)

<div>
  <p id="paragraph" style="font-size: 20px">Lorem ipsum dolor sit
amet, consectetur adipisicing elit,.</p>
</div>
Enter fullscreen mode Exit fullscreen mode
p {
  font-size: 120%; /* option one */
}

div p {
  font-size: 0.5em; /* option two */
}

#paragraph {
  font-size: 10px; /* option three */
}
Enter fullscreen mode Exit fullscreen mode

Load the file in your browser, Use "Inspect Element" on the paragraph, you will get an output similar to the image below:

Specificity in CSS

From the image above, if we observe the Computed tab, we'll see that the browser is using 20px as the font-size.

This clearly indicates that property declarations in the style attribute takes precedence over the same set of property declarations declared with an id, classes, pseudo-selectors and plain tag selectors. That's why it's given a value of 1 and the specification assign it the letter a.


count the number of ID attributes in the selector (= b)

After the style attribute, property declaration in an id attribute takes precedence over the same set of property declarations in other attributes and elements as demonstrated at the beginning of this post.

id's are given the number 0 and assigned the letter b in the specification.


count the number of other attributes and pseudo-classes in the selector (= c)

This tells us that classes, attribute selectors and pseudo-class takes precedence over type selectors and pseudo-elements. Let's take an example.

<div>
  <p class="paragraph">Lorem ipsum dolor sit amet, et dolore magna aliqua.</p>
</div>
Enter fullscreen mode Exit fullscreen mode
/* property declaration with one tag (div) and a pseudo-selector (:first-child)*/
div:first-child {
  font-size: 50px;
}
.paragraph {
  font-size: 120px;
}
Enter fullscreen mode Exit fullscreen mode

Load the file in your browser and use "Inspect Element" in the paragraph. You will realize the browser opted to apply the property declared with the class. They are assigned the number 0 and the letter c in the specification.

Specificity in CSS


count the number of element names and pseudo-elements in the selector (=d)

Pseudo-elements and tag selectors are last in the chain they are assigned the number 0 and letter d in the specification.

In summary:

  • style : assigned number 1 and letter a
  • id : assigned number 0 and letter b
  • classes, attribute selectors, pseudo-classes: assigned number 0 and letter c
  • type selectors and pseudo-elements: assigned the number and letter d

The default number assigned to this selectors in the specification can be summed up as: 1, 0, 0, 0

Now you might think: will the numbers assigned to these selectors ever change? Yes, except that of the style attribute, it will always be 1 because HTML does not allow duplicate attributes applied to an element and if you make such a mistake, the browser will use the first one and gladly ignore the rest.

Take the code sample below, multiple font-size declarations are applied to the paragraph but only the first is applied by the browser.

<div>
  <p style="font-size: 50px;" style="font-size: 100px;" style="font-size: 200px;">
Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
</div>

Enter fullscreen mode Exit fullscreen mode

A paragraph in HTML with 50px font size applied

And if you use viewsource on your code, you'll see the error highlighted in red.

Duplicate attribute in Viewsource

For the remaining selectors, their number increase based on the number of times they are applied to an element, but the selector higher in ranking will always take precedence irrespective of the number of times you apply any selector that's is lower in precedence. Given the code snippet below:

<div>
  <p id="lot-of-ps" class="p1 p2 p3 p4">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, aliqua.</p>
</div>
Enter fullscreen mode Exit fullscreen mode
#lot-of-ps {
  font-size: 10px;
}

.p1.p2.p3.p4 {
  font-size: 40px;
}
Enter fullscreen mode Exit fullscreen mode

In this case, font-size declared with the id selector will win because it has a higher specificity than all the classes combined. Which gives the following number 0, 1, 4, 0

  • 0 - we did not use a style attribute, so it gets a zero
  • 1 - we had one id selector, hence the number one
  • 4 - we applied four class selectors
  • 0 - we did not use any pseudo-element selector, so it gets a zero

CSS Specificity

Now, what happens if we have no id selector? Take the code snippet below, which CSS selector wins?

  <div>
    <p class="p1 p2 p3 p4">Lorem ipsum dolor sit amet, ut labore et dolore aliqua.</p>
 </div>
Enter fullscreen mode Exit fullscreen mode
.p1.p2.p3.p4 {
  font-size: 40px;
}

div p.p1 {
  font-size: 100px;
}
Enter fullscreen mode Exit fullscreen mode

The first CSS selector will win because it has a specificity value of 0, 0, 4,0:

  • 0 - no style attribute selector
  • 0 - no id selector
  • 4 - four class selectors
  • 0 - we used two tag selector div and p

TOOLS FOR UNDERSTANDING CSS SPECIFICITY

Keegan Street Created a tool CSS Specificity Calculator, it automatically shows the Specificity of your declaration when you type (or paste) in your CSS declaration.

Andy Clarke has a poster illustrating CSS specificity using characters from Star Wars.

Estelle Weyl co-author of CSS The Definitive Guide Visual Presentation for the Web Fourth Edition created specifishity.

Now, what happens when the selectors have the same specificity?

/*0012*/
div p.p1 {
  font-size: 100px;
  color: red;
}

/*0012*/
div p.p1 {
  font-size: 200px;
  color: orange;
}
Enter fullscreen mode Exit fullscreen mode

Which selector will the browser use? That's when the 'C' in CSS comes into play, The Cascade.

That is next.

Top comments (2)

Collapse
 
bqardi profile image
Sune Seifert

0040 will always win over 0012.
The reason the 0012 wins in your example is because you define the css incorrectly (the 0040 will never be applied):
.p1 .p2 .p3 .p4 { ... } (meaning; child within a child within a child...)
Should be:
.p1.p2.p3.p4 { ... } (no spaces, meaning the same element that holds all classes)
And then it wins.

Collapse
 
ziizium profile image
Habdul Hazeez

Thank you! Thank you!! Thank you!!!

I published this article almost three years ago, and the last update was over two years ago. You're the first to spot and report the error. I really do appreciate it.

I have updated the article and removed any details related to the error. Once again, thank you! Have a nice day.