CSS Pseudo-Classes and Pseudo-Elements Reference
A quick-lookup reference of every important pseudo-class and pseudo-element, with examples.
1. Pseudo-Classes: User Interaction
| Selector | Example | Description |
|---|---|---|
:hover | a:hover | Mouse cursor is over element |
:active | .btn:active | Element currently being clicked |
:focus | input:focus | Element has keyboard/pointer focus |
:focus-visible | a:focus-visible | Focus visible only for keyboard (not mouse) |
:focus-within | .form:focus-within | Element or any descendant has focus |
:visited | a:visited | Link was already visited |
:link | a:link | Unvisited link |
2. Pseudo-Classes: Structural
| Selector | Description |
|---|---|
:first-child | First sibling of its parent |
:last-child | Last sibling |
:nth-child(n) | nth child (also accepts odd, even, 2n+1) |
:nth-last-child(n) | From the end |
:only-child | Only child of its parent |
:first-of-type | First element of its type |
:last-of-type | Last element of its type |
:nth-of-type(n) | nth element of its type |
:empty | Element with no children (no whitespace either) |
:root | The root <html> element — use for global variables |
/* Zebra stripe a table */
tr:nth-child(even) { background: rgba(255,255,255,0.05); }
/* First paragraph larger */
article p:first-of-type { font-size: var(--text-lg); }
3. Pseudo-Classes: Form State
| Selector | Applies When |
|---|---|
:checked | Checkbox / radio is checked |
:disabled | Form element is disabled |
:enabled | Form element is enabled |
:required | Input has required attribute |
:optional | Input does not have required |
:valid | Input value passes validation |
:invalid | Input value fails validation |
:placeholder-shown | Placeholder text is visible (empty field) |
:in-range | Number input within min/max range |
:out-of-range | Number input outside min/max |
:read-only | Input with readonly attribute |
input:valid { border-color: hsl(145, 65%, 45%); }
input:invalid { border-color: hsl(0, 75%, 55%); }
input:focus:invalid { box-shadow: 0 0 0 3px rgba(229,62,62,0.3); }
4. Pseudo-Classes: Matching
| Selector | Description |
|---|---|
:not(selector) | Every element that does NOT match |
:is(s1, s2, s3) | Matches any in the list; takes highest specificity |
:where(s1, s2) | Matches any in the list; always specificity zero |
:has(child) | Parent selector — element that contains a match |
/* Style nav links EXCEPT the active one */
.nav__link:not(.active) { opacity: 0.7; }
/* Same heading styles, DRY */
:is(h1, h2, h3) { font-family: var(--font-heading); line-height: 1.2; }
/* Card containing an image gets less padding at top */
.card:has(img) { padding-top: 0; }
/* Highlight form section if ANY input is invalid */
.form-section:has(input:invalid) { border-color: red; }
5. Pseudo-Elements: The :: List
| Selector | Description |
|---|---|
::before | Virtual first child (requires content:) |
::after | Virtual last child (requires content:) |
::first-letter | First character of block text |
::first-line | First rendered line of block text |
::selection | Text highlighted by user |
::placeholder | Input placeholder text |
::marker | List item bullet or number |
::backdrop | Behind a <dialog> element |
::cue | WebVTT cues in <video> tracks |
::file-selector-button | The "Browse" button on <input type="file"> |
/* Custom drop cap */
article p:first-of-type::first-letter {
font-family: var(--font-heading);
font-size: 4rem;
float: left;
line-height: 0.75;
margin: 6px 10px 0 0;
color: var(--color-primary);
}
/* Highlight selection color */
::selection {
background: var(--color-primary);
color: white;
}
/* Custom bullet */
ul.checklist li::marker { content: '✓ '; color: var(--color-success); }
/* Style file input button */
input[type="file"]::file-selector-button {
background: var(--color-primary);
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: var(--radius-md);
cursor: pointer;
}