CSS selectors define which HTML elements a set of CSS rules applies to. Mastering selectors lets you target any element precisely without adding extra classes or IDs. This reference covers every selector type you can use in modern CSS.
Basic Selectors
| Selector | Example | Selects |
|---|---|---|
* | * { } | All elements |
element | p { } | All <p> elements |
.class | .card { } | Elements with class="card" |
#id | #header { } | Element with id="header" |
selector, selector | h1, h2 { } | All <h1> and <h2> elements |
Combinator Selectors
Combinators describe the relationship between two selectors.
| Combinator | Example | Selects |
|---|---|---|
A B (descendant) | nav a { } | All <a> inside <nav>, at any depth |
A > B (child) | ul > li { } | <li> that are direct children of <ul> |
A + B (adjacent sibling) | h2 + p { } | First <p> immediately after <h2> |
A ~ B (general sibling) | h2 ~ p { } | All <p> siblings after <h2> |
Attribute Selectors
Target elements based on their attributes and attribute values.
| Selector | Example | Selects |
|---|---|---|
[attr] | [disabled] { } | Elements with the disabled attribute |
[attr="value"] | [type="text"] { } | Exact match |
[attr~="value"] | [class~="card"] { } | Attribute contains word in space-separated list |
[attr|="value"] | [lang|="en"] { } | Value is en or starts with en- |
[attr^="value"] | [href^="https"] { } | Attribute starts with value |
[attr$="value"] | [src$=".png"] { } | Attribute ends with value |
[attr*="value"] | [class*="btn"] { } | Attribute contains value anywhere |
[attr="value" i] | [type="text" i] { } | Case-insensitive match |
Pseudo-Classes — State
These apply when an element is in a specific state.
| Selector | Selects |
|---|---|
:hover | Element being hovered by the pointer |
:focus | Element that has keyboard focus |
:focus-visible | Element that has focus and the browser thinks a focus indicator should be shown |
:focus-within | Element that contains a focused element |
:active | Element being activated (clicked/tapped) |
:visited | Links that have been visited |
:link | Unvisited links |
:target | Element whose id matches the URL fragment |
:checked | Checked checkboxes, radio buttons, or selected options |
:indeterminate | Checkboxes/radios in an indeterminate state |
:disabled | Disabled form elements |
:enabled | Enabled form elements |
:required | Form elements with the required attribute |
:optional | Form elements without required |
:valid | Form elements passing validation |
:invalid | Form elements failing validation |
:in-range | Input elements within their min/max range |
:out-of-range | Input elements outside their min/max range |
:placeholder-shown | Input elements currently showing placeholder text |
:read-only | Elements that are not editable |
:read-write | Elements that are editable |
:default | The default button or form element |
Pseudo-Classes — Structural
These select elements based on their position in the document tree.
| Selector | Selects |
|---|---|
:first-child | First child of its parent |
:last-child | Last child of its parent |
:only-child | Element with no siblings |
:nth-child(n) | nth child (1-indexed) |
:nth-last-child(n) | nth child from the end |
:first-of-type | First element of its type among siblings |
:last-of-type | Last element of its type among siblings |
:only-of-type | Element with no siblings of the same type |
:nth-of-type(n) | nth element of its type |
:nth-last-of-type(n) | nth element of its type from the end |
:root | The document root element (<html>) |
:empty | Elements with no children (including text nodes) |
nth-child Formulas
The n in :nth-child() accepts formulas:
| Formula | Selects |
|---|---|
:nth-child(3) | The 3rd child |
:nth-child(2n) | Even children (2, 4, 6…) |
:nth-child(2n+1) | Odd children (1, 3, 5…) |
:nth-child(even) | Even children |
:nth-child(odd) | Odd children |
:nth-child(3n) | Every 3rd child (3, 6, 9…) |
:nth-child(n+4) | 4th child and beyond |
:nth-child(-n+3) | First 3 children only |
:nth-child(n+2):nth-child(-n+5) | Children 2 through 5 |
Pseudo-Classes — Functional
| Selector | Selects |
|---|---|
:is(selector) | Matches any of the listed selectors. Forgiving (ignores invalid selectors). |
:where(selector) | Same as :is() but with zero specificity. |
:not(selector) | Elements that do not match the selector. |
:has(selector) | Parent elements that contain a matching descendant. The “parent selector.” |
/* Style cards that contain an image */
.card:has(img) {
padding: 0;
}
/* Style any heading */
:is(h1, h2, h3, h4) {
font-weight: bold;
}
/* Style links that are not in nav */
a:not(nav a) {
text-decoration: underline;
}
Pseudo-Elements
Pseudo-elements target specific parts of an element rather than the element itself.
| Selector | Creates/Selects |
|---|---|
::before | Inserts content before the element’s content |
::after | Inserts content after the element’s content |
::first-line | The first line of a block element |
::first-letter | The first letter of a block element |
::placeholder | Placeholder text in form inputs |
::selection | Text selected/highlighted by the user |
::marker | The bullet or number of a list item |
::backdrop | The backdrop behind a <dialog> or fullscreen element |
/* Add a decorative arrow after links */
a.external::after {
content: " \2192";
}
/* Style the first letter of a paragraph */
p::first-letter {
font-size: 2em;
color: var(--accent);
}
Specificity
When multiple selectors target the same element, specificity determines which rules win.
| Selector Type | Specificity | Example |
|---|---|---|
| Inline styles | 1-0-0-0 | style="color: red" |
| ID selectors | 0-1-0-0 | #header |
| Class, attribute, pseudo-class | 0-0-1-0 | .card, [type], :hover |
| Element, pseudo-element | 0-0-0-1 | div, ::before |
Universal (*), combinators | 0-0-0-0 | *, >, +, ~ |
:where() | 0-0-0-0 | Always zero specificity |
:is(), :not(), :has() | Uses highest specificity of its arguments |
Explore selectors interactively with the CSS Selectors Reference tool.