CSS pseudo-classes let you select elements by state, position, or relationship without adding classes to the HTML. Use :hover for pointer interaction, :focus-visible for visible keyboard focus, :nth-child() for sibling positions, and :has() when a matching relationship should affect an element.
What is a CSS pseudo-class?
A pseudo-class is a selector that matches an element based on information beyond its name, attributes, or position in the document tree—for example, whether a link is being hovered, a checkbox is checked, or an element occupies a particular sibling position. The matched element is the selector’s anchor.
Write a pseudo-class with one colon and its name, optionally followed by arguments in parentheses:
selector:pseudo-class
selector:functional-pseudo-class(argument)
For example, button:hover matches a button while it is under the pointer, and li:nth-child(2) matches the second child in a sibling list. Some pseudo-classes are dynamic: interaction can change whether an element matches without changing the document itself. The W3C Selectors Level 4 specification defines pseudo-classes as selectors for special states or information that other simple selectors cannot conveniently express.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Pseudo-class versus pseudo-element
A pseudo-class selects an existing element in a state or context. A pseudo-element represents a particular part of an element, such as generated content or the first line of text. Use one colon for pseudo-classes and the modern double-colon form for pseudo-elements:
a:hover { text-decoration: underline; }
p::before { content: "Note: "; }
The older single-colon spelling remains supported for the legacy pseudo-elements ::before, ::after, ::first-line, and ::first-letter; use double colons in new code.
Interaction and focus pseudo-classes
Interaction states can overlap. A link may be hovered, focused, and active at different moments or under certain input conditions; these selectors are not mutually exclusive.
| Pseudo-class | What it matches | Typical use |
|---|---|---|
:hover |
An element designated by a pointing device | Pointer feedback; do not make essential information available only on hover. |
:active |
An element while it is being activated | Brief pressed-state feedback. |
:focus |
An element that has input focus | Focus styling where focus needs to be indicated. |
:focus-visible |
An element when the browser determines visible focus indication is appropriate | Keyboard-friendly focus rings that follow browser input-modality heuristics. |
:focus-within |
An element that has focus itself or contains a focused descendant | Highlighting a form row while one of its controls has focus. |
Keep keyboard focus visible
A pointer click may not show the same ring as keyboard navigation; browsers use heuristics to decide when :focus-visible applies. Preserve a clear focus indicator rather than removing outlines without a replacement.
Recommended Free Tools
Rank #2
.button:focus-visible {
outline: 3px solid deepskyblue;
outline-offset: 3px;
}
@supports not selector(:focus-visible) {
.button:focus {
outline: 3px solid deepskyblue;
outline-offset: 3px;
}
}
The fallback applies the same visible treatment with :focus where the browser does not support the selector test. MDN’s :focus-visible guide illustrates keyboard and pointer behavior and this fallback pattern.
Structural pseudo-classes: selecting by sibling position
:first-child and :last-child select the first or last element child among siblings. :first-of-type and :last-of-type first restrict the sibling set to the same element type. This difference matters when different elements are mixed together.
/* First child of its parent, whatever its element type */
.item:first-child { margin-top: 0; }
/* First paragraph among paragraph siblings */
p:first-of-type { margin-top: 0; }
:nth-child() and :nth-last-child() count from the beginning or end of the sibling set. Their formulas use An+B: n runs through non-negative integers, while A and B determine the repeating interval and offset.
/* Every even child */
li:nth-child(even) { background: #f5f5f5; }
/* Positions 1, 4, 7, 10, ... */
li:nth-child(3n + 1) { font-weight: 700; }
/* Second child counted from the end */
li:nth-last-child(2) { border-bottom: 0; }
In the first example, even is equivalent to 2n. In 3n + 1, substituting 0, 1, 2, and 3 for n gives positions 1, 4, 7, and 10.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #3
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Count only siblings that match a selector
Selectors Level 4 allows an of <selector-list> filter. The filtered form counts only siblings that match the filter, rather than all element children:
/* Select the second sibling with class item */
:nth-child(2 of .item) { outline: 1px solid; }
This is different from .item:nth-child(2), which first selects elements with class item and then requires the element to be the second child overall.
Form-state pseudo-classes
Form pseudo-classes reflect native control states and semantics. They can often replace a duplicated state class when the form control already carries the relevant state.
| Selector | State it represents |
|---|---|
:checked |
A selected checkbox, radio button, or applicable option. |
:disabled / :enabled |
Whether a control is disabled or enabled. |
:required / :optional |
Whether a control is required or not required. |
:valid / :invalid |
Whether the control satisfies its applicable validity constraints. |
:read-only |
A control that cannot be edited by the user. |
:placeholder-shown |
A control currently displaying placeholder text. |
input:required:invalid { border-color: firebrick; }
input:required:valid { border-color: seagreen; }
input:disabled { opacity: 0.6; }
input:checked + label { font-weight: 700; }
Do not communicate errors or checked state through color alone. Pair styling with clear labels and appropriate error text.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Rank #4
Logical selectors and selecting by relationships
:is(), :where(), and :not() help compose selectors. :has() matches an anchor element when its relative selector describes a relationship that exists.
| Selector | Purpose | Specificity behavior |
|---|---|---|
:is(...) |
Match an element matching any listed alternative. | Uses the specificity of the most specific argument. |
:not(...) |
Exclude elements matching its argument. | Uses the specificity of the most specific argument. |
:where(...) |
Group alternatives without increasing selector specificity. | Always contributes zero specificity. |
:has(...) |
Match an anchor based on a relative selector relationship. | Uses the specificity of the most specific argument. |
Use :has() for a specific relationship
/* A card with a direct image child */
.card:has(> img) { display: grid; }
/* A section containing an h2 descendant */
section:has(h2) { padding-block-start: 1rem; }
/* An anchor containing an image */
a:has(> img) { display: inline-block; }
The anchor is the element before :has()—for example, .card or section. The selector inside the parentheses defines the relationship to test. Thus :has(> img) requires a direct child image; it is not a universal “select any parent” command. A :has() cannot be nested inside another :has(). Check compatibility against the browsers your project supports; MDN’s CSS selectors guide provides selector references, while the specification defines the selector behavior.
Group alternatives without making overrides harder
/* Shared heading rule; :where() adds no specificity */
:where(article, aside) :is(h2, h3) {
line-height: 1.2;
}
/* Any heading, but not one marked muted */
h2:not(.muted) { color: #222; }
Use :where() when a grouping selector should not make later overrides more difficult. Remember that :is() and :not() inherit the specificity of their most specific argument, rather than simply adding one class-level unit.
Document location and state
:target matches the element whose ID corresponds to the URL fragment. It can make an in-page link destination easier to locate. :root matches the document root, normally the <html> element in an HTML document. :empty matches an element with no child content according to the selector’s rules.
Best Value
:target {
scroll-margin-top: 5rem;
background: #fff4c2;
}
:root { color-scheme: light dark; }
Specificity: what happens when rules compete?
Ordinary pseudo-classes contribute class-level specificity. Functional selectors have special rules: :is(), :not(), and :has() take the specificity of their most specific argument; :where() contributes none. The selector list inside the of filter of :nth-child() or :nth-last-child() contributes its most specific selector in addition to the pseudo-class.
When a rule wins unexpectedly, compare the whole selector and the arguments inside its functions. Do not assume every functional pseudo-class adds just one class-level unit. Lower-specificity grouping with :where() can make component styles easier to override.
How to choose the right pseudo-class
- For pointer feedback, start with
:hover; also ensure essential actions and information work without a pointer. - For keyboard navigation, provide an obvious focus style, commonly with
:focus-visibleand a suitable fallback where needed. - For repeated layouts, choose between
:nth-child()and:nth-of-type()based on whether you mean all element siblings or only siblings of the same type. - For native form state, use the corresponding state selector such as
:checked,:disabled, or:invalid. - For alternatives, use
:is(); for exclusions, use:not(); for a zero-specificity group, use:where(). - For a relationship-based match, use
:has()only after confirming the relative selector expresses the intended direct-child or descendant relationship and that target browsers support it.
Or skip the browser setup
If your goal is to capture a rendered example page rather than configure a browser screenshot script, ScreenshotNeo can return an image or PDF from one GET request. Cookie and consent banners are accepted and removed before the shot, along with 60+ known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://developer.mozilla.org/en-US/docs/Web/CSS/:hover -o shot.webp
See the ScreenshotNeo API documentation for request options. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for free screenshots.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsScreenshotNeo is a website screenshot API and MCP server for developers, made by Yorker Media. Learn more at ScreenshotNeo.
Frequently Asked Questions
Is `:focus` the same as `:focus-visible`?
No. `:focus` matches an element with input focus; `:focus-visible` matches when the browser determines a visible focus indicator should be shown.
What does `:nth-child(2 of .item)` count?
It counts only siblings matching `.item` and selects the second one in that filtered set.
Can `:has()` select a parent?
It can match an anchor based on a relationship to another element, including a child or descendant, but the relative selector inside `:has()` determines exactly what relationship qualifies.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




