Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 15

CSS Specificity: Resolving Style Conflicts

Recommended resources

Hello! In our previous lesson, we explored how to enrich elements by adding background colors and images, giving you the tools to create more visually dynamic pages. We ended with a question: what happens when more than one style rule targets the same element?

This lesson answers that very question. You'll learn about CSS specificity, which is the set of rules the browser uses to decide which style declaration "wins" when there's a conflict. Understanding this is not just academic; it's one of the most critical skills for debugging CSS and building predictable, maintainable stylesheets. By the end of this lesson, you'll be able to confidently resolve conflicting styles and structure your CSS like a professional.

Why Do Styles Conflict?

As you build more complex websites, you'll inevitably write rules that overlap. For example, you might set a general style for all paragraphs to have black text, but then want a specific paragraph with a class of highlight to have red text. This isn't an error; it's a fundamental feature of CSS that allows you to layer styles from general to specific.

The browser needs a logical system to resolve these conflicts. This system has two main parts: the cascade (source order) and specificity (selector weight).

Let's start with a quick video that introduces this problem and the role of source order.

WTF is CSS Specificity?

The video "WTF is CSS Specificity?" from the Slaying The Dragon channel provides a very clear, step-by-step introduction to this topic.

Watch the first part of the video, from the beginning until the explanation of source order. It shows that when two identical selectors conflict, the one that appears last in the stylesheet wins. This is the "cascade" in action.


The Scoring System: An Introduction to Specificity

As you just saw, source order matters, but it's only a tie-breaker. A more powerful mechanism is at play: specificity. Think of specificity as a scoring system. Every selector you write gets a score, and the selector with the higher score wins, regardless of its order in the stylesheet.

The video you just started continues by explaining this point system.

WTF is CSS Specificity?

Let's continue with the same video to see how a more "specific" selector can override the source order.

Please watch from this next segment. Notice how applying a class selector (.title) makes that rule "stronger" than the element selector (h1), even though the class rule appears first.


Calculating Specificity

So how is this score calculated? The browser uses a hierarchy of selector types. At a high level, the order of importance from highest to lowest is:

  1. Inline Styles (styles written directly in an HTML tag's style attribute)
  2. ID selectors (e.g., #main-header)
  3. Class, attribute, and pseudo-class selectors (e.g., .nav-item, [href], :hover)
  4. Element and pseudo-element selectors (e.g., h1, ::before)

The universal selector (*) and combinators (>, +, ~) do not add any specificity.

This hierarchy is visualized nicely in the image below.

This diagram illustrates the four main categories used for calculating CSS specificity, ordered from highest (Inline) to lowest (elements & pseudo-elements) weight.

A common way to represent a selector's score is with a three-part value, often written as (A, B, C), where:

  • A = Number of ID selectors
  • B = Number of class, attribute, and pseudo-class selectors
  • C = Number of element and pseudo-element selectors

When comparing two selectors, the browser first compares the A values. The higher one wins. If they are tied, it compares the B values. If those are also tied, it compares the C values. Only if all three numbers are identical does the browser use source order as the tie-breaker.

This "column-based" comparison is crucial. It means even a selector with a million class selectors (e.g., a score of (0, 1000000, 0)) will never beat a selector with just one ID (a score of (1, 0, 0)).

Let's dive into a resource that formalizes this calculation.

Specificity

This article from web.dev provides a modern and accurate explanation of specificity calculation using the triad notation.

First, read the introduction and the section on how to compare specificities to solidify your understanding of the (A,B,C) triad. Then, review the section Selectors influence specificity, which details how each type of selector increments the A, B, or C value.

Let's see this in action with a concrete example. Consider the selector ul#nav li.active a.

This image breaks down the selector `ul#nav li.active a` into its components, calculating a specificity score of (0, 1, 1, 3) in a four-part notation, which corresponds to (1, 1, 3) in our triad, plus an extra category for inline styles.

Let's calculate the specificity using our (A, B, C) triad:

  • ID selectors (A): There is one ID, #nav. So, A = 1.
  • Class selectors (B): There is one class, .active. So, B = 1.
  • Element selectors (C): There are three elements, ul, li, and a. So, C = 3.

The final specificity score for ul#nav li.active a is (1, 1, 3).


The Ultimate Overrides: Inline Styles and !important

There are two things that operate outside this standard calculation.

  1. Inline Styles: A style applied directly to an element using the style attribute (e.g., <p style="color: red;">) will always override any selector in your external stylesheets, no matter how high its specificity score is.

  2. The !important Rule: You can add !important to the end of any CSS property value (e.g., color: blue !important;). This declaration will override everything else, including inline styles.

While !important is powerful, it should be used with extreme caution. It's considered a last resort because it breaks the natural flow of the cascade and can make your CSS incredibly difficult to debug and maintain. A common professional guideline is to only use it when you need to override third-party styles that you cannot edit directly.

Handling conflicts - Learn web development | MDN

The Mozilla Developer Network (MDN) documentation provides authoritative guidance on these special cases.

Please read the short sections covering Inline styles and the !important flag. Pay special attention to the note from MDN strongly recommending you avoid using !important.


Best Practices for Managing Specificity

Now that you know the rules, the goal isn't to create super-high specificity selectors to win every time. The goal is the opposite: to write CSS with low, consistent specificity so that it remains predictable and easy to manage.

Here are the key best practices:

  • Prefer Classes: Use classes to style almost everything. This keeps most of your selectors in the same specificity bracket ((0, 1, 0)), which means source order becomes the primary way to resolve conflicts, which is much easier to reason about.
  • Avoid IDs for Styling: Because IDs have such high specificity, they are difficult to override. It's better to reserve them as JavaScript hooks or for page fragment anchors (e.g., page.html#section2) and use classes for applying styles.
  • Avoid Overly Long Selectors: A selector like .main-content .sidebar .widget .latest-posts ul li a is brittle and has unnecessarily high specificity. A simple class like .widget-link applied directly to the <a> tag is far more robust and reusable.
  • Never Use !important in Your Own Author Stylesheets: Just don't. If you feel the need to, it's almost always a sign that you should refactor your selectors to be more logical.

Kevin Powell gives an excellent summary of these professional habits.

CSS Specificity explained

This final clip from Kevin Powell's video on specificity summarizes the best practices for writing clean, maintainable CSS.

Watch his recommendations from this concluding section. His advice to use classes generously and keep selectors simple is the professional standard.


Practice Time

Let's apply what you've learned to your project. Open your styles.css file.

  1. Add the following HTML to your index.html, perhaps just before the closing </body> tag:

    <div id="practice-section">
      <p class="special-text">A paragraph for practice.</p>
    </div>
    
  2. Now add this CSS to your styles.css file. Before you save and refresh, predict what color the paragraph will be and why.

    /* What color will the paragraph be? */
    
    
    
    
    #practice-section p {
      color: green; /* Specificity: (1, 0, 1) */
    }
    
    .special-text {
      color: red;   /* Specificity: (0, 1, 0) */
    }
    
    p {
      color: blue;  /* Specificity: (0, 0, 1) */
    }
    

    Prediction check: The text will be green. Even though the p rule is last, and the red rule targets the class directly, the #practice-section p selector has an ID in it, giving it a score of (1,0,1). This beats the class selector's score of (0,1,0) and the element selector's score of (0,0,1).

  3. Challenge: How could you make the text red without changing the HTML, and without using !important or an inline style?

    Solution: You need to make the selector for the red color more specific than the one for the green color. You could do this:

    
    
    
    #practice-section .special-text {
      color: red; /* Specificity: (1, 1, 0) */
    }
    

    Now this selector has a score of (1,1,0), which beats the green selector's score of (1,0,1) because the second number (the class count) is higher.


Conclusion

You've just mastered one of the most fundamental concepts in CSS. Understanding specificity frees you from the frustration of styles not applying as expected and empowers you to write clean, logical, and debuggable code.

Key Takeaways:

  • The browser resolves conflicting CSS rules using a system of specificity and source order.
  • Specificity is calculated based on a hierarchy: IDs are more specific than classes, which are more specific than elements.
  • You can think of specificity as a three-part score (IDs, Classes, Elements). The browser compares these scores from left to right to determine the winner.
  • If two selectors have the exact same specificity score, the one that appears last in the stylesheet (the cascade) wins.
  • Inline styles override all stylesheet selectors, and !important overrides everything. Both should be used sparingly, if at all.
  • The best practice is to keep specificity low and consistent by primarily using single class selectors to style your elements.

Now that we have a solid grasp on styling individual elements, we'll shift our focus to how elements are arranged on the page. In the next lesson, we'll explore the CSS display property, learning the difference between block and inline elements. This is the first step toward creating complex page layouts.