CSS Specificity + Selectors Cheat Sheet

Introduction

CSS can feel unpredictable when styles don’t apply the way you expect, but most of the time there’s a logical reason behind it. Understanding how selectors work — and how specificity determines which rule wins — turns CSS from something frustrating into something controlled and intentional. This guide breaks down the core selector types, explains how specificity is calculated, and shows practical examples so you can write cleaner styles and debug issues with confidence instead of guesswork.

Specificity rules

CSS specificity determines which rule “wins” when multiple selectors target the same element. It works like a scoring system. The higher the score, the more powerful the selector. Inline styles have the highest specificity, followed by IDs, then classes/attributes/pseudo-classes, and finally type selectors (like div, p, h1).

Think of specificity like a hierarchy:

p { color: blue; } .text { color: green; } #main { color: red; }

If a <p> inside #main also has class="text", the text will be red. The ID selector beats the class and the type selector because it has higher specificity.

Attribute selectors

Attribute selectors allow you to target elements based on attributes instead of classes or IDs. These are incredibly useful when styling forms or dynamic elements.

Basic syntax looks like this:

input[type="text"] { border: 2px solid blue; }

This selects only text inputs, not checkboxes or radio buttons. Attribute selectors can also match partial values:

a[href^="https"] { color: green; }

The ^= means “starts with.” So this targets links that begin with https.

Attribute selectors have the same specificity level as class selectors. That means they beat type selectors but lose to IDs.

Pseudo-classes

Pseudo-classes target elements in a specific state. They don't select based on structure — they select based on behavior or condition.

The most common example is :hover:

button:hover { background-color: black; color: white; }

This applies only when the mouse is hovering over the button.

Another critical one is :focus, especially for accessibility:

input:focus { outline: 3px solid orange; }

This activates when a user tabs into an input field. It's essential for keyboard users.

Pseudo-classes have the same specificity weight as classes. So:

button:hover

has the same specificity level as:

.button

This is why order in your stylesheet matters when specificity is equal.

Combining selectors

Combining selectors increases specificity and allows you to target elements more precisely.

For example:

nav a { color: blue; }

This targets all <a> elements inside <nav>.

Now compare that to:

nav a.active { color: red; }

This selector is more specific because it includes a class. It targets only links inside nav that also have the class active.

You can also combine IDs and classes:

#navbar .nav-link { font-weight: bold; }

This targets elements with class nav-link inside the element with id navbar.

Each additional class, attribute, or pseudo-class increases specificity. But stacking too many can make debugging harder — so keep selectors intentional, not complicated.

Debugging “why isn't my style applying?”

When a style isn't applying, it's almost always one of these reasons:

  1. A more specific selector is overriding it.
  2. The rule appears earlier in the stylesheet.
  3. The selector is incorrect.
  4. The element doesn't actually match the selector.

Example:

p { color: blue; } .article p { color: green; }

If your <p> is inside .article, it will be green. The second selector is more specific.

Another common issue is order:

.button { background: red; } .button { background: blue; }

The button will be blue because the second rule appears later.

When debugging:

Once you understand specificity and selector types, CSS stops feeling random. It becomes predictable. And that’s when layout bugs start to feel solvable instead of mysterious.