CSS Selectors Cheatsheet
Basic Selectors
| Selector | Syntax | Matches |
|---|---|---|
| Universal | * | Every element |
| Element | div | All <div> elements |
| Class | .card | Elements with class="card" |
| ID | #nav | Element with id="nav" |
| Attribute | [href] | Elements that have href attribute |
| Attribute = | [type="text"] | Exact value match |
| Attribute ^= | [href^="https"] | Value starts with |
| Attribute $= | [href$=".pdf"] | Value ends with |
| Attribute *= | [class*="btn"] | Value contains |
| Attribute ~= | [class~="active"] | Space-separated word match |
| Multi-class | .card.featured | Has BOTH classes |
| Group | h1, h2, h3 | Any of these selectors |
Combinators
| Combinator | Syntax | Matches |
|---|---|---|
| Descendant | nav a | <a> anywhere inside <nav> |
| Child | ul > li | <li> direct child of <ul> only |
| Adjacent sibling | h2 + p | <p> immediately after <h2> |
| General sibling | h2 ~ p | All <p> after <h2> at same level |
| Column | `col |
Pseudo-Classes: Interaction
| Pseudo-class | When It Applies |
|---|---|
:hover | Mouse over element |
:focus | Element has keyboard focus |
:focus-visible | Focus via keyboard (not mouse) — use this for custom focus rings |
:focus-within | Element or any descendant is focused |
:active | Being clicked/pressed |
:visited | Visited link |
:link | Unvisited link |
Pseudo-Classes: Form State
| Pseudo-class | Matches |
|---|---|
:checked | Checked checkbox or radio |
:disabled | Disabled form control |
:enabled | Enabled form control |
:required | Has required attribute |
:optional | Does NOT have required |
:valid | Input passes validation |
:invalid | Input fails validation |
:in-range | Value within min/max |
:out-of-range | Value outside min/max |
:placeholder-shown | Placeholder is currently displayed |
:user-valid | Valid after user interaction |
:user-invalid | Invalid after user interaction |
:read-only | Has readonly attribute |
:read-write | Is editable |
Pseudo-Classes: Structural
| Pseudo-class | Matches |
|---|---|
:first-child | First child of its parent |
:last-child | Last child of its parent |
:only-child | Only child of its parent |
:nth-child(n) | nth child (1-indexed) |
:nth-child(odd) | Every odd child: 1, 3, 5... |
:nth-child(even) | Every even child: 2, 4, 6... |
:nth-child(3n) | Every 3rd: 3, 6, 9... |
:nth-child(3n+1) | 1, 4, 7, 10... |
:nth-last-child(n) | nth from the end |
:first-of-type | First of its tag type |
:last-of-type | Last of its tag type |
:nth-of-type(n) | nth of its tag type |
:only-of-type | Only element of that tag in parent |
:empty | No children or text |
:root | The <html> element |
:target | ID matches URL hash |
:scope | Scoped reference point |
Pseudo-Classes: Functional (Modern)
| Pseudo-class | Use | Specificity |
|---|---|---|
:is(h1, h2, h3) | Match any in list | Highest in list |
:not(.active) | Exclude matches | Highest arg specificity |
:where(h1, h2) | Match any in list | Always 0 |
:has(> img) | Parent has matching child | Highest arg specificity |
:has(input:focus) | Parent of focused input | — |
Pseudo-Elements
| Pseudo-element | What It Creates/Targets |
|---|---|
::before | Generates first child (needs content:) |
::after | Generates last child (needs content:) |
::first-line | First rendered line of text |
::first-letter | First letter (drop cap) |
::selection | Text selected by user |
::placeholder | Input placeholder text |
::marker | List item bullet/number |
::backdrop | Behind <dialog> or fullscreen element |
::file-selector-button | File input button |
::spelling-error | Misspelled text (browser-determined) |
::-webkit-scrollbar | Scrollbar (Chrome/Edge) |
::-webkit-scrollbar-thumb | Scrollbar draggable handle |
Specificity Quick Reference
[inline] [IDs] [classes/attrs/pseudo-classes] [elements/pseudo-elements]
1 1 1 1
Examples:
style="" = 1,0,0,0
#id = 0,1,0,0
.class, [attr], :hover = 0,0,1,0
div, ::before = 0,0,0,1
* = 0,0,0,0
:is(), :not(), :has() → specificity of their most specific argument
:where() → always 0,0,0,0
Selector Patterns: Quick Copy
/* All headings */
:is(h1, h2, h3, h4, h5, h6) { }
/* Everything except header and footer */
main *:not(header, footer) { }
/* Sibling spacing (lobotomized owl) */
* + * { margin-top: 1em; }
/* First child: no top margin */
.c-stack > :first-child { margin-top: 0; }
/* Last child: no bottom margin */
.c-stack > :last-child { margin-bottom: 0; }
/* Parent of invalid input */
.c-form__group:has(input:invalid) { border-color: var(--color-danger); }
/* Card with image: remove top padding */
.c-card:has(> img:first-child) { padding-top: 0; }
/* Links that open in new tab */
a[target="_blank"]::after { content: ' ↗'; }
/* External links */
a[href^="http"]:not([href*="yourdomain.com"]) { }
/* Zebra table rows */
tr:nth-child(even) { background: var(--color-surface-2); }
/* Last except last (border between items, not after last) */
.c-list__item:not(:last-child) { border-bottom: 1px solid var(--color-border); }