CSS Selectors Guide: Types, Combinators, and Specificity

Published Updated

A CSS selector is the part of a rule that decides which elements on the page get styled. Get the selector right and the rest of CSS calms down a lot. Most of the styling bugs you will chase early on come from a selector matching too much, too little, or losing a fight with another rule you forgot was there. This guide is part of our CSS guide series.

How Do CSS Selectors Target Elements?

CSS selectors match elements by tag name, class, ID, or other characteristics. The browser applies a style rule’s declarations to the elements its selector matches:

p {
  line-height: 1.5;
}

.card {
  padding: 1rem;
}

#site-header {
  position: sticky;
  top: 0;
}

The class selector is the one you will use most of the time, because a class can sit on as many elements as you want. Keep your selectors readable and you will usually be able to predict what they hit before you even reload the page.

A type selector like p reaches every paragraph in the document, which makes it right for a document-wide default and wrong the moment one paragraph needs to look different. An id selector sits at the other extreme, matching only the one element that carries it, since an id is supposed to be unique on the page. Classes live in between, giving you a repeatable hook for however many elements share that look.

How Do CSS Combinators Connect Selectors?

CSS combinators connect selectors by the relationship between elements. A space between two selectors means "any descendant," and the > symbol means "direct child only":

.menu a {
  color: var(--color-link);
}

.menu > li {
  margin-block: 0.25rem;
}

That first rule reaches every link inside .menu, however deeply nested. The second rule only touches list items that are immediate children of .menu, which is exactly what you want when nesting could otherwise leak your styles somewhere surprising.

Combinators add no specificity of their own, only the selectors on either side of the symbol count toward the score. So .menu > li and .menu li carry identical weight even though the child combinator is far more precise about what it hits. Pick the tighter combinator for correctness, since it wins no specificity fight.

When Does CSS Specificity Decide Which Rule Wins?

CSS specificity decides between matching declarations only after origin, importance, and cascade layer have been resolved. Within that comparison, IDs outrank classes and classes outrank type selectors. A more specific selector cannot override a declaration that already won at an earlier cascade stage.

#promo .button {
  background: rebeccapurple;
}

.button {
  background: gray;
}

The button inside #promo ends up purple even though the gray rule comes later in the file, because the id pushes the first selector's score higher. When you understand how that number gets built, you stop reaching for !important to force a result.

That score is three tiers compared in order: ids first, then classes and pseudo-classes, then tags. A selector only needs to win the leftmost tier to beat a rival, no matter how many classes the losing selector piles on afterward.

Why Should You Avoid Overcomplicated Selectors?

Overcomplicated CSS selectors tie your styles to the current HTML structure and make overrides harder. Before adding another class or !important, inspect the winning rule in developer tools. Check whether your selector matches at all, then fix the actual conflict.

Topics

TopicWhat it coversGuide
Selector basicsType, class, and id selectors and when to use eachSelector Basics
CombinatorsDescendant, child, and sibling relationshipsCombinators
Pseudo-classesState and position selectors like :hover and :nth-child()Pseudo-classes
SpecificityHow the cascade scores selectors and resolves conflictsSpecificity

Frequently Asked Questions

Are CSS selectors case-sensitive?

CSS type selectors such as div are case-insensitive in HTML. Class and ID selectors are case-sensitive in standards-mode HTML, so .myBox and .mybox match different class names. XML documents have different case rules.

Do complex selectors slow a page down?

Complex CSS selectors can add work during style calculations, especially on large, frequently changing pages. Start by making selectors readable and predictable, then profile the page before treating selector complexity as a performance problem.

Can a CSS selector match an element based on its text?

CSS cannot select an element by matching an arbitrary word or substring in its text. Add a class or data attribute for that purpose, or use JavaScript. Selectors such as :empty can detect some structural conditions but cannot search text.

What is the difference between a CSS selector and a rule?

A CSS selector identifies the elements to style. A CSS style rule contains that selector and the declarations inside the braces. A comma-separated selector list lets one rule target several groups of elements.

Can CSS select an element using multiple attributes?

CSS attribute selectors can be chained so every condition must match the same element. For example, input[type="email"][required] selects required email inputs. Attribute selectors also support prefix, suffix, and substring matching.

Sources

  1. [1]
    Specificity
    (developer.mozilla.org)
  2. [2]
    Class selectors
    (developer.mozilla.org)
  3. [3]
    Descendant combinator
    (developer.mozilla.org)