CSS Pseudo-Classes Table
| Pseudo-class | Matches |
|---|---|
| :hover | Element under the pointer (does not require click) |
| :focus | Element that has keyboard or programmatic focus |
| :focus-visible | Focus from keyboard only (not mouse click) |
| :active | Element being activated (mouse button held down) |
| :visited | Link that has already been visited |
| :first-child | Element that is the first child of its parent |
| :last-child | Element that is the last child of its parent |
| :nth-child(n) | Element at position n among its siblings (supports odd, even, 2n+1) |
| :nth-of-type(n) | Element at position n among siblings of the same type |
| :checked | Checkbox or radio button that is selected |
| :disabled | Form element that is disabled |
| :required | Form element with the required attribute |
| :invalid | Form element that fails constraint validation |
| :placeholder-shown | Input element currently showing placeholder text |
| :root | The html element (useful for CSS custom properties) |
| :empty | Element with no children (including text nodes) |
| :not(selector) | Element that does NOT match the given selector |
| :is(selector) | Element matching any of the listed selectors (specificity of most specific) |
| :where(selector) | Like :is() but contributes zero specificity |
CSS pseudo-classes style elements based on state or position rather than class or ID - :hover for mouse interaction, :nth-child(2n) for every other row, :invalid for failed form validation. This table covers all 19 pseudo-classes verbatim from MDN, organised by what triggers them.
The two modern additions that changed the game: :focus-visible (focus rings only for keyboard users, not mouse clicks) and :where() (zero-specificity grouping that can be overridden by any class).
How to use
- Filter by pseudo-class name or category - hover, child, form, link - to find the one you need.
- Click any pseudo-class to copy it into your CSS.
- Read the matches column for the exact triggering condition - some are surprising (:focus fires on mouse click for inputs, but :focus-visible does not).
Frequently asked questions
What is the difference between :focus and :focus-visible?
:focus triggers whenever an element receives focus, including mouse clicks on inputs. :focus-visible only triggers when the browser determines the user is navigating by keyboard (typically Tab key). The result: keyboard users see focus rings, mouse users do not - solving the old problem of removing outline: none and breaking accessibility.
How does :nth-child(odd) work?
It selects every other element starting from the first: elements at positions 1, 3, 5, 7... The general form :nth-child(an+b) selects elements at positions a·n + b for n = 0, 1, 2... So :nth-child(2n) is even positions and :nth-child(2n+1) is odd positions. You can also use :nth-child(3) for exactly the third element.
What is the specificity difference between :is() and :where()?
:is() takes the specificity of its most specific argument, while :where() always contributes zero. This means :where(section, #sidebar) p has the same specificity as just p, making it perfect for reset styles that should be easily overridden by any class or utility.
Why does :first-child sometimes not match?
:first-child means the first child element of any type, not the first element of a specific type. If a div contains a text node followed by a p, the p is :first-child (text nodes are not elements). If it contains a span followed by a p, the p is NOT :first-child - the span is. Use :first-of-type for type-specific matching.