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; }
Every h1 on the page.

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.

SelectorMatches
[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.

SelectorSpecificity (a, b, c)
*0, 0, 0
li0, 0, 1
.card0, 1, 0
a[href]0, 1, 1
#main1, 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.