DEV Community

Cover image for Understanding CSS Specificity: What It Is and How It Works
Eleftheria Batsou
Eleftheria Batsou

Posted on

Understanding CSS Specificity: What It Is and How It Works

When it comes to creating styles for web pages, Cascading Style Sheets (CSS) is the preferred tool of many developers. However, there is one aspect of CSS that can be a source of confusion: specificity.

Specifically, how does CSS determine which style rules will be applied when multiple rules apply to the same element? That’s where specificity comes into play.

What is CSS Specificity?

CSS Specificity refers to the set of rules that determines which CSS rule applies to an element on a web page. The specificity of a selector is measured by how detailed it is. In general, the more specific a rule is, the more weight it carries.

How CSS Specificity is Calculated

Specificity is calculated based on the number of elements, classes, IDs, and pseudo-classes that are contained within a rule. The specific order of how the values are defined is important, and it goes as follows:

  1. Inline styles
  2. IDs
  3. Classes, attributes, and pseudo-classes
  4. Elements and pseudo-elements

In terms of specificity, each category carries more weight than the one before it. For example, #id is considered more specific than .class, which is more specific than element.

To determine the specificity of a particular rule, you add up the number of occurrences of each of these selectors in the rule. For example:

div .myclass p {
  font-size: 24px;
}
Enter fullscreen mode Exit fullscreen mode

This rule applies the font-size property to all p elements that are children of an element with class="myclass", which is in turn a descendant of a div element. The CSS specificity of this example is:

  • Element selector: 1
  • Class selector: 1
  • Descendant combinator (space): 1
  • Total specificity: 1-1-1

The Four Levels of Specificity

There are four distinct levels of specificity in CSS:

  1. The Universal Selector. This selector has a specificity of 0, meaning it has no impact on specificity calculations at all. It’s represented by an asterisk – *.

  2. Type Selectors and Pseudo-Elements. Type selectors apply to elements of a specific type, such as div, p, or a. They have a specificity of 1. Pseudo-elements ::before and ::after can also be included in this category because they aren't technically "selectors" but do affect specificity. They also have a specificity of 1.

  3. Class Selectors, Attribute Selectors, and Pseudo-Classes. Class selectors begin with a period (.), attribute selectors use brackets ([ ]), and pseudo-classes are preceded by a colon (:). They all have a specificity of 10.

  4. ID Selectors. IDs are selected using a hash (#), and they have the highest specificity level of 100.

To put this in perspective, consider the following CSS rules:

#menu a {...} /* specificity: 100 + 1 = 101 */
.main-nav a {...} /* specificity: 10 + 1 = 11 */
a {...} /* specificity: 1 */
Enter fullscreen mode Exit fullscreen mode

Here, the #menu selector has the highest specificity, at 101. #menu a is more specific than .main-nav a, so its style rules will overrule the other. Meanwhile, a applies to all elements, so its rules will be applied last.

Specificity and The Use of Combinators

One of the things that can make CSS specificity tricky is the use of combinators, which are used to combine or relate different elements in a selector. The main combinator types are:

  1. Descendant combinator - represented by a space - which selects elements that are descendants of the first element.
  2. Child combinator - represented by the greater-than symbol > - which selects only direct child elements of the first element.
  3. Adjacent sibling combinator - represented by a plus sign + - which selects the first sibling immediately following the first element.
  4. General sibling combinator - represented by a tilde ~ - which selects all siblings that follow the first element.

To put this in perspective, check out the following examples:

  1. Descendant combinator - adds 0 points
body p { /* 0 points */ }
Enter fullscreen mode Exit fullscreen mode
  1. Child combinator > - adds 1 point
nav > ul { /* 1 point */ }
Enter fullscreen mode Exit fullscreen mode
  1. Adjacent sibling combinator + - adds 1 point

h2 + p { /* 1 point */ }

  1. General sibling combinator ~ - adds 0 points
h2 ~ p { /* 0 points */ }
Enter fullscreen mode Exit fullscreen mode

It's important to note that combinators can add points to the specificity of a selector, but they do not affect the priority of selectors with higher specificity values.

CSS Specificity with Embedded and Inline Styles

CSS specificity can also vary depending on where the styles are defined, and how they are defined.

For example:

Embedded Styles

<head>
  <title>CSS Specificity Example</title>
  <style>
    h1 {
      color: red; /* specificity: 1 */
    }

    #header h1 {
      color: blue; /* specificity: 101 */
    }
  </style>
</head>
<body>
  <div id="header">
    <h1>CSS Specificity Example</h1>
  </div>
</body>
Enter fullscreen mode Exit fullscreen mode

Here we have two rules for h1 tags – one with a specificity of 1, and one with a specificity of 101. The #header h1 rule should be more specific and override the h1 rule, but both are defined in a stylesheet embedded within the head section of the HTML document.

Inline Styles

<body>
  <div id="header">
    <h1 style="color: green;">CSS Specificity Example</h1>
  </div>
</body>
Enter fullscreen mode Exit fullscreen mode

In this example, the color of the h1 element is defined within an inline style. According to our specificity hierarchy, an inline style has a specificity of 1000. Therefore, it would override any other conflicting styles by default.

Overriding CSS Specificity

There are several ways to override CSS specificity rules. Here are two common ones:

Using Important

p {
  color: red !important; /* specificity: 1 */
}

.text-italic {
  color: blue; /* specificity: 10 */
}
Enter fullscreen mode Exit fullscreen mode

In this example, the color of all p elements will be red because of the !important keyword added to the rule.

Using Selectors

p#paragraph {
  color: blue;
}

.text-italic p {
  color: red;
}
Enter fullscreen mode Exit fullscreen mode

Here, all paragraphs with id="paragraph" will be blue, but all paragraphs that are descendants of elements with class text-italic will be red.

Advanced Examples

As a general rule, selectors to the right have higher specificity than those to the left, so a.special is more specific than .special, but less specific than p#large.special.

Here are some more examples that illustrate how CSS specificity works:

What is the color of the paragraph in each example?

Example 1/2

<p class="red">
  I'm a red paragraph!
</p>

<style>
  p.red {
    color: red;
  }

  .red {
    color: blue;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

The paragraph element will have red text as the CSS selector .red is more specific than the class selector p.red. The p.red selector has a specificity of 11, as class selectors have ten points and the element selector has one.

Example 2/2

<div>
 <p id="green">
   I'm a green paragraph!
 </p>
</div>

<style>
  div #green {
    color: green;
  }

  #green {
    color: blue;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

In this example, the paragraph element will have green text as the CSS selector div #green is more specific than the ID selector #green. The div #green selector has a specificity of 12, while the #green selector has a specificity of 100. Here, the specific selector div #green wins over the less specific ID selector #green.

Tips to Remember

Here are 3 tips to remember before start styling your page:

1️⃣ Inline style attributes have a higher specificity value than any other type of selector.

<p id="my-id" class="my-class" style="color: red;">Inline styles win!</p>
Enter fullscreen mode Exit fullscreen mode

In the example above, the color of the paragraph will be red, even though the ID selector has a higher specificity value.

2️⃣Pseudo-classes and pseudo-elements have their own specificity values.

.my-class:focus { /* 1 point */ }

.my-class::before { /* 1 point */ }
Enter fullscreen mode Exit fullscreen mode

In the example above, both the :focus pseudo-class and the ::before pseudo-element have a specificity value of 1 point.

3️⃣ Specificity values can be calculated using the specificity npm package or online calculators.

const getSpecificity = require('specificity');

const selectors = [
  'p',
  '.my-class',
  '#my-id',
  'body p',
  'nav > ul',
  'h2 + p',
  'h2 ~ p',
  '.my-class:focus',
  '.my-class::before'
];

selectors.forEach(selector => {
  console.log(getSpecificity(selector)[0].specificity);
});
Enter fullscreen mode Exit fullscreen mode

In the example above, we can calculate the specificity values of each selector using the specificity npm package.

By keeping these additional points in mind, you can gain a deeper understanding of how specificity works in CSS and how to use it effectively in your code.

Conclusion

CSS specificity can seem complicated at first, but it's an essential concept to master for any web developer. By understanding how specificity and combinator selectors work, you can ensure that your styles are consistently applied to HTML elements, without running into specificity conflicts or other issues that can cause your website to display incorrectly.

With the examples above, you can gain a better understanding of how specificity works in practice and how to apply it to your CSS stylesheets. Keep practicing and experimenting with CSS specificity, and you'll be a pro in no time!

Resources and References

  1. MDN Web Docs: Specificity
  2. CSS Tricks: Specifics on CSS Specificity

👋 Hello, I'm Eleftheria, devrel and content creator.

🥰 If you liked this article, consider sharing it.

🌈 All links | Twitter | LinkedIn | Book a meeting

Top comments (1)

Collapse
 
fruntend profile image
fruntend

Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍