Why Isn't Your CSS Working? Understanding Specificity

Ever felt like screaming at your CSS because it won’t apply your styles? You tweak a color, refresh… nothing. Or worse, some rule overrides it. The culprits? CSS Cascading and Specificity—the forces deciding which styles win. Specificity isn’t just a beginner’s hurdle—I’ve seen it frustrate seasoned developers as well. I’ve been there myself. This is part one of our “Why Isn’t Your CSS Working?” series. Before tackling cascading, you must master specificity, the ranking system that decides which styles apply over others. Many tutorials teach cascading first, but without understanding specificity, it feels unpredictable. Mastering it now makes cascading much clearer in the next part. While writing this article, I considered all the real-world problems I’ve faced—many of which both beginners and advanced devs deal with daily. At the end of this article, you’ll get a case study to cement your understanding and a quiz to test it. This is theory-heavy, but trust me, it’ll make CSS far less frustrating in the future. Let’s dive in! Table of Contents What is Specificity? Specificity Calculation (The Simple Formula) In Depth How Combined Selectors Affect Specificity Ranking Specificity of Inline CSS, Internal CSS, External CSS An Exception in CSS Specificity – !important Specificity in Action (A Case Study) Bottom Line Quick Quiz: Strengthen Your Understanding of the Specificity Wrapping Up SOLUTION OF THE QUIZ What is Specificity? Specificity determines which CSS rule takes precedence when multiple rules apply to the same element. The general rule is: more specific rules override less specific ones. Think of specificity as a ranking system. For example, in the military, a lieutenant can give orders in the absence of a general. However, if the general is present, their orders take priority over the lieutenant’s because they hold a higher rank. Similarly, in CSS, a more specific rule will always override a less specific one. Specificity Calculation (The Simple Formula) in depth Now that you understand what specificity is, let’s break down how it’s calculated. The easiest way to think about specificity is to assign a score to each type of selector. We’ll use a ranking system to make specificity easier to understand. If we assign ranks to a a selector: A → High Rank B → Medium Rank C → Low Rank If combined, the ranking increases → AB is stronger than A or AC, just as BC is stronger than B or C. If the same rank appears multiple times, the last one takes priority → For example, if AB appears first and another AB appears later, the second one will override the first. (Which is known as cascading, which will be discussed in the next part of this series.) The Specificity Formula (ID count, Class/Attribute/Pseudo-class count, Element/Pseudo-element count) Feeling overwhelmed? No worries! Let’s break it down step by step. 1. Understanding Specificity of an ID Selector Suppose we write CSS for an element using an ID selector: #myElement { color: blue; } Let’s apply the specificity formula by replacing the values: ID count = 1 (since we are using a single ID selector) Class/Attribute/Pseudo-class count = 0 (since no classes, attributes, or pseudo-classes are used) Element/Pseudo-element count = 0 (since no element names or pseudo-elements are used) Thus, the specificity value is: (1, 0, 0) Why does 1 in place of The ID count appear in the first position? CSS specificity prioritizes ID selectors, giving them the highest weight. That’s why they always take the first position in the specificity tuple. Since ID selectors uniquely identify elements, they have high specificity, so we assign them Rank A. This is the specificity of an ID selector. This is easier than it looks, isn't it? 2. Understanding Specificity of Class/Attribute/Pseudo-class Selector Now that we’ve assigned values for an ID selector, understanding Class, Attribute, and Pseudo-class selectors becomes easier. Let’s start with the Class Selector. 1. Class Selector Here’s our specificity formula again: (ID count, Class/Attribute/Pseudo-class count, Element/Pseudo-element count) For class selectors, we replace the Class/Attribute/Pseudo-class count portion with 1, just like we did for ID selectors, but in its respective position. Let’s see it in action: /* Class Selector Example */ .button { color: blue; } Since we are selecting an element by its class name, we assign: ID count = 0 (No ID selector used) Class/Attribute/Pseudo-class count = 1 (One class selector used) Element/Pseudo-element count = 0 (No element or pseudo-element used) Thus, the specificity value is: (0, 1, 0) Since class selectors have a lower specificity than ID selectors, we assign them Rank B. 2. Attribute Selector /* Attribute Selector Example */ input[type="text"] {

Apr 9, 2025 - 08:06
 0
Why Isn't Your CSS Working? Understanding Specificity

Ever felt like screaming at your CSS because it won’t apply your styles? You tweak a color, refresh… nothing. Or worse, some rule overrides it. The culprits? CSS Cascading and Specificity—the forces deciding which styles win.

Specificity isn’t just a beginner’s hurdle—I’ve seen it frustrate seasoned developers as well. I’ve been there myself.

This is part one of our “Why Isn’t Your CSS Working?” series. Before tackling cascading, you must master specificity, the ranking system that decides which styles apply over others.

Many tutorials teach cascading first, but without understanding specificity, it feels unpredictable. Mastering it now makes cascading much clearer in the next part.

While writing this article, I considered all the real-world problems I’ve faced—many of which both beginners and advanced devs deal with daily. At the end of this article, you’ll get a case study to cement your understanding and a quiz to test it.

This is theory-heavy, but trust me, it’ll make CSS far less frustrating in the future. Let’s dive in!

Table of Contents

  1. What is Specificity?
  2. Specificity Calculation (The Simple Formula) In Depth
  3. How Combined Selectors Affect Specificity Ranking
  4. Specificity of Inline CSS, Internal CSS, External CSS
  5. An Exception in CSS Specificity – !important
  6. Specificity in Action (A Case Study)
  7. Bottom Line
  8. Quick Quiz: Strengthen Your Understanding of the Specificity
  9. Wrapping Up
  10. SOLUTION OF THE QUIZ

What is Specificity?

Specificity determines which CSS rule takes precedence when multiple rules apply to the same element. The general rule is: more specific rules override less specific ones.

Think of specificity as a ranking system. For example, in the military, a lieutenant can give orders in the absence of a general. However, if the general is present, their orders take priority over the lieutenant’s because they hold a higher rank. Similarly, in CSS, a more specific rule will always override a less specific one.

Specificity Calculation (The Simple Formula) in depth

Now that you understand what specificity is, let’s break down how it’s calculated. The easiest way to think about specificity is to assign a score to each type of selector.

We’ll use a ranking system to make specificity easier to understand. If we assign ranks to a a selector:

  • A → High Rank
  • B → Medium Rank
  • C → Low Rank
  • If combined, the ranking increasesAB is stronger than A or AC, just as BC is stronger than B or C.
  • If the same rank appears multiple times, the last one takes priority → For example, if AB appears first and another AB appears later, the second one will override the first. (Which is known as cascading, which will be discussed in the next part of this series.)

The Specificity Formula

(ID count, Class/Attribute/Pseudo-class count, Element/Pseudo-element count)

Feeling overwhelmed? No worries! Let’s break it down step by step.

1. Understanding Specificity of an ID Selector

Suppose we write CSS for an element using an ID selector:

#myElement {
    color: blue;
}

Let’s apply the specificity formula by replacing the values:

  • ID count = 1 (since we are using a single ID selector)
  • Class/Attribute/Pseudo-class count = 0 (since no classes, attributes, or pseudo-classes are used)
  • Element/Pseudo-element count = 0 (since no element names or pseudo-elements are used)

Thus, the specificity value is:

(1, 0, 0)

Why does 1 in place of The ID count appear in the first position?

CSS specificity prioritizes ID selectors, giving them the highest weight. That’s why they always take the first position in the specificity tuple.

Since ID selectors uniquely identify elements, they have high specificity, so we assign them Rank A.

This is the specificity of an ID selector. This is easier than it looks, isn't it?

2. Understanding Specificity of Class/Attribute/Pseudo-class Selector

Now that we’ve assigned values for an ID selector, understanding Class, Attribute, and Pseudo-class selectors becomes easier. Let’s start with the Class Selector.

1. Class Selector

Here’s our specificity formula again:

(ID count, Class/Attribute/Pseudo-class count, Element/Pseudo-element count)

For class selectors, we replace the Class/Attribute/Pseudo-class count portion with 1, just like we did for ID selectors, but in its respective position.

Let’s see it in action:

/* Class Selector Example */
.button {
    color: blue;
}

Since we are selecting an element by its class name, we assign:

  • ID count = 0 (No ID selector used)
  • Class/Attribute/Pseudo-class count = 1 (One class selector used)
  • Element/Pseudo-element count = 0 (No element or pseudo-element used)

Thus, the specificity value is:

(0, 1, 0)

Since class selectors have a lower specificity than ID selectors, we assign them Rank B.

2. Attribute Selector

/* Attribute Selector Example */
input[type="text"] {
    border: 1px solid red;
}

For an attribute selector like [type="text"], the specificity is:

(0, 1, 0)

Because:

  • ID count = 0 (No ID selector used)
  • Class/Attribute/Pseudo-class count = 1 (One attribute selector used)
  • Element/Pseudo-element count = 0 (No element or pseudo-element used)

Since it has the same specificity as a class selector, we also assign it Rank B.

3. Pseudo-class Selector

/* Pseudo-class Selector Example */
a:hover {
    text-decoration: underline;
}

A pseudo-class like :hover follows the same rule:

(0, 1, 0)
  • ID count = 0 (No ID selector used)
  • Class/Attribute/Pseudo-class count = 1 (One pseudo-class used)
  • Element/Pseudo-element count = 0 (No element or pseudo-element used)

Just like class and attribute selectors, pseudo-classes hold Rank B.

Why does 1 in place of Class/Attribute/Pseudo-class count appear in the second position?

CSS specificity prioritizes Class, Attribute, and Pseudo-class selectors after ID selectors, giving them the second highest weight. That’s why they always take the second position in the specificity tuple.

This covers the Class, Attribute, and Pseudo-class selectors. Their specificity is equal, making them more powerful than element selectors but weaker than ID selectors.

3. Understanding Specificity of Element/Pseudo-element Selector

Now that we’ve covered Class, Attribute, and Pseudo-class selectors, understanding Element and Pseudo-element selectors is straightforward. These selectors have the lowest specificity in CSS.

1. Element Selector

Here’s our specificity formula again:

(ID count, Class/Attribute/Pseudo-class count, Element/Pseudo-element count)

For element selectors, we replace the Element/Pseudo-element count portion with 1, while keeping the other values as 0.

Let’s see it in action:

/* Element Selector Example */
p {
    font-size: 16px;
}

Since we are selecting an element by its tag name, we assign:

  • ID count = 0 (No ID selector used)
  • Class/Attribute/Pseudo-class count = 0 (No class, attribute, or pseudo-class used)
  • Element/Pseudo-element count = 1 (One element selector used)

Thus, the specificity value is:

(0, 0, 1)

Since element selectors have the lowest specificity, we assign them Rank C.

2. Pseudo-element Selector

/* Pseudo-element Selector Example */
p::before {
    content: "Note: ";
    font-weight: bold;
}

A pseudo-element like ::before or ::after follows the same rule:

(0, 0, 1)
  • ID count = 0 (No ID selector used)
  • Class/Attribute/Pseudo-class count = 0 (No class, attribute, or pseudo-class used)
  • Element/Pseudo-element count = 1 (One pseudo-element used)

Since pseudo-elements behave like elements in specificity calculations, they share Rank C with element selectors.

Why does 1 in place of Element/Pseudo-element count appear in the third position?

CSS specificity does not prioritize Element/Pseudo-element selectors as highly as Class, Attribute, Pseudo-class, or ID selectors, giving them the lowest weight. That’s why they always take the third position in the specificity tuple.

Still, there is a lower level of specificity available—the most lowest—and we are going to explore it in this next section.

4. Understanding Specificity of the Universal Selector

Now that we've explored ID selectors, class/attribute/pseudo-class selectors, and element/pseudo-element selectors, let's look at the universal selector *.

The universal selector applies to all elements, but it holds the lowest possible specificity in CSS.

Let’s revisit our specificity formula:

(ID count, Class/Attribute/Pseudo-class count, Element/Pseudo-element count)

Universal Selector Example

/* Universal Selector Example */
* {
    margin: 0;
    padding: 0;
}

Let’s break this down using the specificity formula:

  • ID count = 0 (No ID selector used)
  • Class/Attribute/Pseudo-class count = 0 (No class, attribute, or pseudo-class used)
  • Element/Pseudo-element count = 0 (No element or pseudo-element used)

So the specificity of the universal selector is:

(0, 0, 0)

Why is the universal selector the weakest?

The universal selector * is designed to target everything, but with no priority. It acts like a default fallback. That’s why it holds zero specificity — it’s not targeting any specific type, class, or ID.

You can think of it as a private in the military ranking analogy — it follows all orders but can't override anyone.

Finalizing CSS Ranking System:

  • Rank AID selectors (1, 0, 0)
  • Rank BClass, Attribute, Pseudo-class selectors (0, 1, 0)
  • Rank CElement, Pseudo-element selectors (0, 0, 1)

We now understand that Rank A (ID selectors) overrides Rank B (Class, Attribute, Pseudo-class selectors), which in turn overrides Rank C (Element, Pseudo-element selectors) — and all universal selectors get overridden by all of them.

But what happens when we combine multiple selectors? Can a compound selector (a combination of classes, attributes, or pseudo-classes) override an ID selector?

How Combined Selectors Affect Specificity Ranking

We have seen how different ranks (A, B, and C) influence which styles take precedence. But what happens when we combine or repeat them?

1. Combination of A and B (AB)

When A (high rank) and B (medium rank) are combined, the result is stronger than A or B alone. This makes AB more dominant than a standalone A or B.

#id.class {
  color: blue;
}

Or Descendant Selector (A B)

.container p {
  color: blue;
}

or Child Selector (A > B)

.container > p {
  color: red;
}

Or Adjacent Sibling Selector (A + B)

h2 + p {
  margin-top: 0;
}

Or General Sibling Selector (A ~ B)

h2 ~ p {
  color: gray;
}
  • Rank: (1, 1, 0)
  • Since it contains both A and B, it is stronger than a single A or B.

2. Combination of B and C (BC)

When B (medium rank) and C (low rank) are combined, the result becomes stronger than B or C alone, but still weaker than any selector containing A.

.class div {
  font-size: 16px;
}

Or Descendant Selector (B C)

.container span {
  color: blue;
}

Or Child Selector (B > C)

.box > h2 {
  color: red;
}

Or Adjacent Sibling Selector (B + C)

.note + h4 {
  margin: 10px 0;
}

Or General Sibling Selector (B ~ C)

.alert ~ h2 {
  font-weight: bold;
}
  • Rank: (0, 1, 1)
  • Since it contains both a class and an element selector, it’s stronger than either alone, but cannot beat a selector with an ID.

3. Repeating A (AA)

If A (ID selectors) appears more than once in a selector chain, the specificity doubles, making it stronger than any combination of B and C, but with one catch: you cannot apply more than one ID to a single element in valid HTML.

Invalid example (for concept only):

#id1#id2 {
  background: red;
}

Valid and practical form:

 id="container">
   id="item">Hello