← Back to blog
Why CSS Specificity Works the Way It Does

Why CSS Specificity Works the Way It Does

#css#internals#deepdive

Why CSS Specificity Works the Way It Does

CSS specificity is a fundamental concept in web development, and yet many developers don't fully understand how it works. In this article, we will delve into the deeper mechanics behind CSS specificity to reveal why it operates the way it does.

The Surface-Level Understanding of CSS Specificity

At a high level, CSS specificity refers to the order in which styles are applied when there are conflicts between them. When a selector matches multiple elements and has conflicting styles, the browser uses the specificity rules to determine which style to apply.

For example, consider two selectors that both target an h1 element:

h1 {
  color: red;
}

div h1 {
  color: blue;
}

Both of these selectors match the same h1 element, but one has a higher specificity than the other. In this case, the second selector has two classifiers (an element and an element-level pseudo-class) while the first selector only has one classifier (an element). As a result, the second selector wins because it has a higher specificity.

The Deeper Reality of CSS Specificity

The specificity rules are based on a hierarchical system that prioritizes styles based on their level of specificity. Here's how it works:

  1. Universal Selector: * is the most unspecific selector in CSS, as it matches any element. It has a specificity value of 0, which means it can be overridden by any other selector with a higher specificity.
  2. Element Selectors: Element selectors are the most specific type of selector, as they target a single element. For example, h1 is an element selector that targets all h1 elements on the page. Its specificity value is 1.
  3. Class Selectors: Class selectors are also very specific, as they target elements based on their class attribute. For example, .className targets all elements with a class attribute containing "className". Its specificity value is 2.
  4. ID Selectors: ID selectors are the most specific type of selector, as they target a single element based on its ID attribute. For example, #idName targets the element with an ID of "idName". Its specificity value is 3.
  5. Pseudo-classes and Pseudo-elements: These selectors are also very specific, as they target elements based on their state or position in the document tree. For example, :hover targets all elements that are currently being hovered over, while ::after targets the pseudo-element after an element. Their specificity value is 4.
  6. Attribute Selectors: Attribute selectors are less specific than other types of selectors, as they target elements based on their attributes. For example, [href] targets all elements with a non-empty href attribute. Its specificity value is 5.
  7. Combinators and Negation: Combinators and negation selectors are also less specific than other types of selectors, as they combine or exclude other selectors from a set of matches. For example, h1 + p targets all p elements that follow an h1 element, while :not(h1) excludes any h1 elements from the match. Their specificity value is 6.
  8. The cascade: The last factor in determining specificity is the cascade order, which refers to the order in which styles are applied when there are multiple conflicting selectors. In this case, the most recent selector in the DOM wins.

Code Examples That Reveal the Truth About CSS Specificity

Here are some examples that demonstrate the deeper mechanics of CSS specificity:

/* Example 1 */
div p {
  color: blue;
}

p {
  color: red;
}

/* The above selector will not override the `color` style of the paragraph,
   as it is targeting a more specific element (the `div`). */
/* Example 2 */
span {
  color: blue;
}

p span {
  color: red;
}

/* The above selector will override the `color` style of any `span` that is a child of a paragraph,
   as it has a higher specificity value than the first selector. */

Why This Matters in Practice

Understanding CSS specificity is crucial for writing maintainable and scalable CSS code. Here are some real-world scenarios where understanding specificity can prevent bugs or improve performance:

  1. Debugging: When debugging a web page, it's essential to know the order of styles in the cascade and how they interact with each other. Understanding specificity can help you identify which selector is causing a conflict and fix it quickly.
  2. Performance optimization: By optimizing the order of selectors in the cascade, you can improve the performance of your web page by reducing the amount of work the browser needs to do. This is especially important for large or complex pages with many stylesheets.
  3. Avoiding specificity wars: When working on a team or collaborating on a project, it's easy to accidentally overwrite each other's styles. Understanding specificity can help you avoid these conflicts and keep your codebase organized and maintainable.

The Key Insight

The key insight behind CSS specificity is that it's not just about the order of selectors in the cascade, but also about their specificity values. By understanding how to use each selector type effectively, you can write more efficient and scalable CSS code that works across all browsers.