loading...

CSS Specificity

ziizium profile image Habdul Hazeez Updated on ・6 min read

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>
p {
  font-size: 120%; /* option one */
}

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

#paragraph {
  font-size: 10px; /* option three */
}

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>
p {
  font-size: 120%; /* option one */
}

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

#paragraph {
  font-size: 10px; /* option three */
}

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>
/* property declaration with one tag (div) and a pseudo-selector (:first-child)*/
div:first-child {
  font-size: 50px;
}
.paragraph {
  font-size: 120px;
}

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>

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>
#lot-of-ps {
  font-size: 10px;
}

.p1 .p2 .p3 .p4 {
  font-size: 40px;
}

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>
.p1 .p2 .p3 .p4 {
  font-size: 40px;
}

div p.p1 {
  font-size: 100px;
}

The second CSS selector wins, which gives us the following 0, 0, 1, 2

  • 0 - no style attribute selector
  • 0 - no id selector
  • 1 - we used a class selector
  • 2 - we used two tag selector div and p

The first CSS selector will give use the 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

Now you might be wondering: Four class selectors, how come it did not win? Because of the rules of specificity:

  • If a selector has more IDs, it wins (that is, it’s more specific).
  • If that results in a tie, the selector with the most classes wins.
  • If that results in a tie, the selector with the most tag names wins.

From this, we can see that the selector div p.p1 won because it has two tags in it and the selector .p1 .p2 .p3 .p4 lost because it had no tag, just four classes.

CSS Specificity

This might still be confusing, but with lots of experiments and patience, you'll be fine.

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;
}

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

That is next.

Posted on by:

ziizium profile

Habdul Hazeez

@ziizium

I teach and write code with interests in Web Development, Computer Security, and Artificial Intelligence.

Discussion

pic
Editor guide