What a CSS selector is
A selector is the part of a rule before the curly braces. It decides which elements the declarations apply to.
p.note { color: #2563eb; }
/* selector: p.note declaration: color: #2563eb */
The five basic selectors cover most real stylesheets:
Selector types at a glance
| Selector | Example | Matches |
|---|---|---|
| Universal | * | Every element |
| Type | p | Every <p> |
| Class | .tip | Elements with class="tip" (among others) |
| ID | #main-title | The element with id="main-title" |
| Attribute | [type="email"] | Elements whose attribute matches |
| Pseudo-class | a:hover, li:first-child | Elements in a state or position |
| Pseudo-element | p::first-line, .x::before | A part of an element |
| Group | h1, h2, h3 | Anything matching one of the list |
| Compound | p.tip | A <p> that also has the class |
Classes and IDs have their own page, CSS class selector. Pseudo-classes such as :nth-child() and :not() are covered on the pseudo-classes page.
Combinators: descendant vs child
A combinator joins two selectors by their relationship in the HTML tree. There are four.
| Combinator | Syntax | Matches B when |
|---|---|---|
| Descendant | A B (space) | B is anywhere inside A |
| Child | A > B | B's parent is A |
| Adjacent sibling | A + B | B comes right after A, same parent |
| General sibling | A ~ B | B comes somewhere after A, same parent |
The space and the > are the pair people mix up. The descendant selector reaches any depth; the child selector stops at one level:
Sibling combinators: + and ~
Siblings only look forward. There is no "previous sibling" combinator, though :has() can express it: h2:has(+ p) matches an h2 that is directly followed by a p.
Attribute selectors
Square brackets match on attributes and their values:
| Selector | Matches |
|---|---|
[disabled] | Has the attribute, any value |
[type="email"] | Value is exactly email |
[href^="https"] | Value starts with https |
[href$=".pdf"] | Value ends with .pdf |
[class*="icon"] | Value contains icon anywhere |
[lang|="en"] | Value is en or starts with en- |
[data-state="open" i] | Exact match, ignoring case |
Attribute selectors on data-* attributes are a clean way to style state that JavaScript sets, without inventing class names.
Try any selector
Type a selector into the box. Every element it matches gets an amber outline, and the count shows below.
Try #demo a, ul > li, h2 ~ *, a[href^="https"], li:not(.active).
Compound vs descendant: the space matters
p.note and p .note differ by one space and mean different things.
How browsers read selectors
When several rules match the same element and set the same property, the more specific selector wins, and on a tie the later one wins. An ID outweighs any number of classes, and a class outweighs any number of type selectors; the !important page has the full specificity table.
A group has one catch: if any selector in a plain list is invalid, the whole rule is dropped. In a, b:unknown { } not even the links are styled. Wrapping the list in :is() makes it forgiving, so :is(a, b:unknown) still styles the links.
Common mistakes
- Missing the dot or hash.
tip { }targets a<tip>element, notclass="tip". Write.tip. - Space in a compound selector.
p .noteis notp.note. - Expecting
>to reach grandchildren. Use a space for any depth. - One typo breaks a whole group. In
h1, h2:hovr, h3nothing gets styled. - Over-long selectors.
body div.wrapper ul li ais slow to read and hard to override. A single class is usually enough.
Frequently Asked Questions
What is a CSS selector?
The part of a CSS rule before the { that says which elements the declarations apply to. In p.note { color: blue; }, the selector p.note matches every <p> with the class note.
What is the difference between a space and > in a CSS selector?
A space is the descendant combinator: nav a matches every link anywhere inside a nav, at any depth. > is the child combinator: nav > a matches only links whose direct parent is the nav.
What does + mean in CSS?
+ is the adjacent sibling combinator. h2 + p matches a <p> that comes immediately after an <h2> with the same parent. ~ is looser: h2 ~ p matches every later <p> sibling.
How do I select elements by attribute in CSS?
Put the attribute in square brackets: [disabled] matches elements that have it, [type="email"] matches an exact value, [href^="https"] a value that starts with a string, [href$=".pdf"] one that ends with it, and [class*="btn"] one that contains it.
Can CSS select a parent element?
Yes, with the :has() pseudo-class, supported in current Chrome, Firefox and Safari. li:has(> a.active) matches the list items that directly contain an active link.