CSS Selectors
Selector Types
- Universal selectors [MDN]
- Type (element) selectors [MDN]
- Class selectors [MDN]
- ID selectors [MDN]
- Attribute selectors [MDN]
Combinators
Pseudo-Classes
-
:not()
(negation pseudo-class) matches elements which do not match its argument [MDN, spec].- It has been available for many years, but up to CSS Selectors Level 3 it only supported simple selectors as an argument (e.g.
:not(.foo):not(.bar)
). In Selectors Level 4, it was extended to additionally support a selector list (e.g.:not(.foo, .bar)
). [W3, caniuse, W3, caniuse]. :not()
itself is non-forgiving but it can be when nested like:not(:is(/*...*/))
.
- It has been available for many years, but up to CSS Selectors Level 3 it only supported simple selectors as an argument (e.g.
-
:is()
[MDN]- Its evaluation might not be obvious, e.g.
.a .b .c
and.a :is(.b .c)
do not match the exact same elements [bram.us]. This is also relevant when using CSS nesting.
- Its evaluation might not be obvious, e.g.
-
:where()
behaves like:is()
but always has a specificity of 0 [MDN]. -
:has()
itself is non-forgiving but it can be when nested like:has(:is(/*...*/))
[w3c/csswg-drafts#7676]
Specificity
Cascade Layers
- developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_layers
- developer.mozilla.org/en-US/docs/Web/CSS/@layer
- w3.org/TR/css-cascade-5/#layering
- caniuse.com/css-cascade-layers
- css-tricks.com/css-cascade-layers
- bram.us/2021/09/15/the-future-of-css-cascade-layers-css-at-layer
To support older browsers, there is a Cascade Layers polyfill [csstools/postcss-plugins, oddbird.net].
Forgiving Selectors
CSS Nesting
- developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting
- drafts.csswg.org/css-nesting
- caniuse.com/css-nesting
- webkit.org/blog/13813/try-css-nesting-today-in-safari-technology-preview
- developer.chrome.com/articles/css-nesting
The nesting syntax was decided on using a poll [webkit.org, chrome-dev, bram.us].
Lobotomized Owl
The 'lobotomized owl' selector * + *
consists of two universal selectors and an adjacent sibling combinator.
It selects elements that are preceded by an adjacent sibling element.
In other words, everything except the first element is being selected.
This selector is often used to apply margins in between two elements.
It thus allows to define vertical rhythm without having any undesired bottom spacing on the last element.
[alistapart.com]
Several adaptations of the selector and/or the styling it applies exist. One example is to use a generic class name and then apply a variable margin—or a default margin if no specific custom property was defined in the scope. [andy-bell.co.uk]
.flow > * + * {
margin-block-start: var(--flow-space, 1em);
}
The alternative selector .flow > :not(:first-child)
targets the exact same elements.
But it has a higher specificity than the Lobotomized Owl selector.
It is therefore not recommended to use the alternative selector for this use case.