CSS Selectors Cheatsheet
Every CSS selector on one page: basic selectors, combinators, all seven attribute operators, the full pseudo-class catalogue (structural, state, and the modern functional ones like :is(), :where(), :has()), pseudo-elements, and how specificity is calculated.
Basic Selectors
Selector | Example | Matches |
|---|---|---|
Universal |
| Every element |
Type |
| Elements by tag name |
Class |
| Elements with |
ID |
| The element with |
Compound |
| Elements matching all parts (a button that has the class) |
Grouping |
| Any element matching any listed selector |
Combinators
Combinator | Example | Matches |
|---|---|---|
Descendant (space) |
| Any |
Child |
| Only direct children |
Next sibling |
| The first |
Subsequent siblings |
| Every |
article p { line-height: 1.6; } /* any depth */
ul > li { list-style: square; } /* direct child only */
h2 + p { margin-top: 0; } /* immediately after */
input ~ label { color: gray; } /* any later sibling */Attribute Selectors — All 7 Operators
Syntax | Meaning | Example match |
|---|---|---|
| Attribute exists |
|
| Exactly equals |
|
| Contains word |
|
| Exactly |
|
| Starts with |
|
| Ends with |
|
| Contains substring |
|
/* Case-insensitive flag */
a[href$=".PDF" i] { color: crimson; } /* matches .pdf and .PDF */
/* Practical examples */
a[href^="http"]:not([href*="mysite.com"])::after {
content: " \2197"; /* mark external links */
}
input[type="checkbox"]:checked + label { font-weight: bold; }Structural Pseudo-classes
Selector | Matches |
|---|---|
| First / last element among its siblings |
| An element with no siblings |
| By position: |
| Same, counting from the end |
| First / last sibling of that tag |
| Position counted among same-tag siblings only |
| Element with no children (not even text) |
| The document root — |
li:nth-child(odd) { background: #f6f6f6; } /* zebra rows */
li:nth-child(3n) { color: teal; } /* every third */
li:nth-child(n + 4) { display: none; } /* from 4th on */
li:nth-last-child(-n + 2) { opacity: 0.5; } /* last two */
p:first-of-type { font-size: 1.2em; } /* lead paragraph */State and UI Pseudo-classes
Selector | Matches |
|---|---|
| Pointer over / being clicked |
| Element has keyboard/programmatic focus |
| Focused and the browser decides a ring should show (keyboard) |
| Element or any descendant is focused |
| Visited / unvisited links (styling is restricted for privacy) |
| Checked checkbox/radio, selected option |
| Form control state |
| Form control validation attributes |
| Form control validity right now |
| Invalid after the user interacted — far less aggressive |
| Input currently showing its placeholder |
| Element whose id matches the URL fragment |
Functional Pseudo-classes: :is(), :where(), :not(), :has()
/* :is() — collapse repetitive selectors.
Specificity = the most specific argument. */
:is(h1, h2, h3) a { text-decoration: none; }
/* :where() — identical matching, but specificity is ZERO.
Perfect for resets and defaults meant to be overridden. */
:where(ul, ol) { margin: 0; padding: 0; }
/* :not() — exclusion. Accepts full selector lists. */
button:not(.primary, .danger) { background: gray; }
/* :has() — the "parent selector". Matches an element
based on what it CONTAINS. */
.card:has(img) { padding: 0; }
form:has(:invalid) .submit { opacity: 0.5; }
h2:has(+ p) { margin-bottom: 0.25em; } /* h2 followed by p */:where() and :is() match identically — the only difference is specificity. :where() contributes zero, while :is() takes the specificity of its most specific argument, even for the parts that did not match.Pseudo-elements
Selector | Targets |
|---|---|
| Generated content inserted inside the element (needs |
| Typographic fragments of block text |
| Text the user has highlighted |
| An input's placeholder text |
| List bullets / numbers |
| The layer behind a modal |
| The button inside |
::before); pseudo-classes use one (:hover). Browsers still accept the legacy single-colon form for the four oldest pseudo-elements, but write double colons in new code.Specificity
Specificity is compared as three numbers (A, B, C) — higher wins, compared left to right. Ties go to the later rule in the stylesheet.
Level | Counts | Examples |
|---|---|---|
A — IDs | Each |
|
B — Classes | Classes, attributes, pseudo-classes |
|
C — Types | Tag names and pseudo-elements |
|
Zero |
| Contribute nothing |
Special | Inline | — |
/* Worked examples */ p /* (0,0,1) */ .intro /* (0,1,0) */ p.intro /* (0,1,1) */ #main p.intro /* (1,1,1) */ a:hover /* (0,1,1) */ :is(#nav, p) a /* (1,0,1) — :is takes the max argument */ :where(#nav, p) a /* (0,0,1) — :where is always zero */
Quick Reference: Selector Performance
Browsers match selectors right to left, so the rightmost part (the key selector) matters most. In practice selector speed is almost never your bottleneck — write for readability, and only worry about extremely broad key selectors (like a bare * or [class*=...]) inside huge documents.
Related pages: Specificity, Combinators, The :has() selector, and :is() / :where() / :not().