Basic selectors
The building blocks of every selector: the simple selectors that match by element, class, id or attribute, and the way you combine and list them. Combinators live under Combinators.
Type selector
Matches by element name. p matches every <p> . Case-insensitive in HTML.
h1 { font-size: 2rem; }
Universal selector
* matches every element. Often scoped to a subtree, e.g. section * , or used in resets.
Class selector
.name matches elements whose class attribute contains name . Chain them — .card.featured — to require several at once.
ID selector
#name matches the single element with id="name" . High specificity, so used sparingly for styling.
Attribute selectors
Match on the presence or value of an attribute.
| Selector | Matches |
|---|---|
[attr] | The attribute is present. |
[attr=value] | The value is exactly value. |
[attr~=value] | A space-separated word equals value. |
[attr|=value] | Equals value, or starts value- (language ranges). |
[attr^=value] | The value starts with value. |
[attr$=value] | The value ends with value. |
[attr*=value] | The value contains value. |
Add i before the closing bracket for case-insensitive matching ( [type=email i] ), or s to force case-sensitive.
Selector list
A comma-separated list applies one rule to several selectors — h1, h2, h3 . If any selector in the list is invalid the whole rule is dropped; use :is() to forgive that.
Specificity
When several rules match, specificity decides. It is counted as three numbers: ids, then classes / attributes / pseudo-classes, then type / pseudo-elements.
| Selector | Specificity (a, b, c) |
|---|---|
* | 0, 0, 0 |
li | 0, 0, 1 |
.card | 0, 1, 0 |
a[href] | 0, 1, 1 |
#main | 1, 0, 0 |
The universal selector and combinators add nothing. :is() and :not() take the specificity of their most specific argument; :where() always counts as zero.