Understanding CSS Specificity: The Battle of the Selectors
Have you ever written a CSS rule that you were sure was correct, but it just wouldn't apply? The culprit is almost always CSS Specificity. Specificity is the algorithm browsers use to determine which CSS declaration is the most "specific" and therefore wins the battle when multiple rules target the same element.
The Hierarchy of Specificity
Think of selectors having a score. The selector with the highest score wins. The scoring is ranked as follows, from most powerful to least powerful:
- Inline Styles: A style written directly on an HTML element (e.g.,
style="color: red;"
). This almost always wins. - ID Selectors: A selector targeting an ID (e.g.,
#main-nav
). - Class, Attribute, and Pseudo-class Selectors: Selectors targeting a class (
.button
), an attribute ([type="text"]
), or a pseudo-class (:hover
). - Type Selectors and Pseudo-elements: Selectors targeting an element type (
h1
,div
) or a pseudo-element (::before
).
The universal selector (*
) has no specificity value.
A Practical Example: Who Wins?
Let's look at a simple button. We will try to color it with three different rules.
Example HTML and CSS:
<style>
/* Type selector (LOWEST specificity) */
button {
color: black;
}
/* Class selector (MEDIUM specificity) */
.important-button {
color: blue;
}
/* ID selector (HIGH specificity) */
#submit-btn {
color: red;
}
</style>
<button id="submit-btn" class="important-button">Which color am I?</button>
What's the result? Paste this code into the HTML Viewer. The button text will be **red**. The ID selector #submit-btn
is more specific than the class or type selector, so its rule wins.
Combining Selectors Increases Specificity
When you chain selectors together, their scores add up. This is where things get interesting.
A selector like div .my-class
is more specific than just .my-class
on its own. A selector with two class names like .btn.btn-primary
is more specific than a selector with one class name.
Example of a Combined Selector Winning:
<style>
/* This rule has a higher score because it uses two class selectors */
.btn.btn-danger {
background-color: red;
}
/* This rule has a lower score */
.btn {
background-color: blue;
}
</style>
<button class="btn btn-danger">My background will be red!</button>
<button class="btn">My background will be blue.</button>
Key takeaway: The more specific you are in your selection, the more "weight" your rule carries. This is why it's a good practice to use classes for most styling and avoid overly specific selectors unless necessary.
The Ultimate Power: `!important`
The !important
rule is a special declaration you can add to a CSS property. It will override **any other declaration**, regardless of specificity. It is a "get out of jail free" card, but it should be used with extreme caution.
p {
color: blue !important; /* This will override everything! */
}
#my-paragraph {
color: red; /* This rule will lose, even though ID is more specific */
}
Use `!important` sparingly. Overusing it makes your stylesheet incredibly difficult to debug because it breaks the natural rules of specificity. It's usually a sign that your CSS structure could be simplified.
Write Predictable CSS
Understanding specificity allows you to write CSS that behaves exactly as you expect. By favoring simple class selectors for most of your work and only increasing specificity when needed, you create stylesheets that are clean, predictable, and easy for you and your team to maintain.