CSS Selectors Table
| Selector | Selects | Example |
|---|---|---|
.card | Class - every element carrying it | <div class="card"> |
#header | ID - the one element with it | <header id="header"> |
button | Type - every such element | all <button>s |
*[lang] | Attribute present | any element with a lang attribute |
input[type="checkbox"] | Attribute equals | checkbox inputs only |
nav a | Descendant - any depth | links inside nav, however nested |
nav > a | Child - one level only | direct link children of nav |
h2 + p | Adjacent sibling - immediately after | the first paragraph following an h2 |
h2 ~ p | General sibling - anywhere after | all following paragraph siblings |
a:hover, :focus-visible | Pseudo-class - state | hovered or keyboard-focused links |
p::first-line | Pseudo-element - sub-part | the first rendered line of each paragraph |
li:nth-child(2n) | Structural pattern | even-numbered list items |
nav a is fine but needlessly long chains are slow to match and brittle to maintain. Specificity climbs in the order type < class < id; the discipline that keeps stylesheets sane is staying in class territory and treating ids as JavaScript hooks, not style targets. Bottom line: the three combinators (space, >, +) are three different promises about structure - pick the weakest one that says what you mean. Related tools: pseudo-elements table and pseudo-classes table for the colon families, CSS animations table for what selectors trigger, and specificity calculator for the arithmetic.Selectors are the addressing system of CSS: every style rule is a question about the document, and the selector is how you ask it. The table below is the working twelve - the class, id, type, attribute, combinator and pseudo patterns that cover effectively every rule in a real stylesheet.
Bottom line: the browser matches selectors right to left. It filters elements by the rightmost part first, then walks the remaining conditions leftward - which is why selector length buys you nothing (the rightmost part does the filtering), and why every extra combinator is a structural promise your HTML must keep. Three combinators, three promises: descendant (space) = anywhere inside, child (>) = exactly one level, adjacent sibling (+) = immediately after.
The honest part: specificity is the shadow system underneath. It climbs type < class < id, and stylesheets stay maintainable exactly as long as you stay in class territory - ids as style targets create specificity walls that only inline styles can beat. The pseudo families have their own pages (pseudo-classes for states, pseudo-elements for sub-parts); this table shows where they sit in a compound selector.
How to use
- Find the relationship you need in the table - the Example column shows the HTML each pattern matches.
- Choose the weakest combinator that expresses the structure: descendant when depth is irrelevant, child when only direct nesting counts, adjacent sibling for the follows-immediately case.
- Verify in DevTools: type the selector in the Styles panel filter or run document.querySelectorAll in the console - the live count is the truth.
Frequently asked questions
Why do browsers match CSS selectors right to left?
Because the rightmost part - the key selector - is the cheapest filter. For nav a, the browser first collects every a on the page, then checks which have a nav ancestor. Reading left to right (grab every nav, then search inside for links) does the same job with more bookkeeping. The practical consequence: the last part of your selector does the heavy lifting, so piling on ancestors for precision usually just makes the rule harder to read without changing what it matches.
What is the difference between nav a and nav > a?
The descendant combinator (nav a) matches every link anywhere inside the nav - including links inside dropdown lists three levels deep. The child combinator (nav > a) matches only links that are direct children. They are three different promises: space says anywhere inside, > says exactly one level down, + says immediately after in the same parent. Choosing the weakest one that expresses your intent keeps the rule working when the markup gains a wrapper.
How does specificity actually rank selectors?
Three number slots: id count, class/attribute/pseudo-class count, type/pseudo-element count - compared left to right, like a date. A selector with one id beats any number of classes; a tie falls to the next slot; inline styles beat everything except !important. The maintainable zone is the middle slot: selectors like .nav .link (two classes) stay overridable, while #nav a (one id) creates a wall that later rules can only climb with another id or !important.
What is the difference between :hover and ::before style pseudo syntax?
One colon marks pseudo-CLASSES - states an element can be in (hover, focus, nth-child); two colons mark pseudo-ELEMENTS - sub-parts of an element you can style (::before, ::first-line). Browsers forgive the single-colon form for legacy pseudo-elements, but the double-colon form is the standard and the distinction is worth keeping: a pseudo-class filters which elements match, a pseudo-element styles a piece of one element. The two families on this site have their own reference tables.