Modern selectors make CSS more expressive without long repeated selector lists.
:is()
:is() groups selector options:
:is(h1, h2, h3) {
line-height: 1.15;
}
It matches any listed selector. Its specificity is the specificity of the most specific selector in the list.
Useful for reducing repetition:
.article :is(h2, h3, h4) {
margin-block-start: 2em;
}
:where()
:where() also groups selectors, but has zero specificity:
:where(h1, h2, h3) {
margin-block: 0;
}
This is excellent for base styles that should be easy to override.
.prose :where(ul, ol) {
padding-inline-start: 1.5em;
}
:not()
:not() excludes matches:
.nav-link:not([aria-current="page"]) {
color: inherit;
}
Use it for simple exclusions. If a selector becomes a paragraph of exceptions, split the CSS into clearer classes or states.
:has()
:has() selects an element based on what it contains or relates to:
.field:has(input:required) label::after {
content: " *";
}
It can also look at state:
.card:has(:focus-visible) {
outline: 3px solid royalblue;
outline-offset: 4px;
}
Or choose layout based on content:
.media-card:has(img) {
display: grid;
grid-template-columns: 8rem 1fr;
gap: 1rem;
}
Specificity with modern selectors
:is(), :not(), and :has() use the specificity of the most specific selector in their argument list.
:where() always adds zero specificity.
That makes :where() useful in resets and base layers:
@layer base {
:where(a) {
color: var(--link);
}
}
Components can override it easily:
@layer components {
.button {
color: white;
}
}
Browser support strategy
For newer selectors, check MDN, Baseline, and caniuse for your target browsers. When a selector is an enhancement, wrap it:
@supports selector(.card:has(img)) {
.card:has(img) {
display: grid;
grid-template-columns: 8rem 1fr;
}
}
The base .card style still works if :has() is unavailable.
What to carry forward
:is()groups selectors with normal specificity behavior:where()groups selectors with zero specificity:not()excludes matches:has()selects based on descendants, siblings, or state relationships- use
@supports selector(...)for progressive enhancement when support matters - modern selectors help most when paired with clear HTML and low-specificity CSS
The next lesson covers native CSS nesting and scoped styling.