CSS :has() Can Select a Parent
CSS :has() lets a selector match an element based on what is inside or next to it. It is often described as a parent selector, although relative selectors make it useful for more than parents.
This selector matches an <a> only when it has a direct <img> child:
a:has(> img)
The > matters. Without it, an image anywhere inside the link would match.
Looking at the next sibling
:has() can also look forward in the document. This matches a <dt> immediately followed by another <dt>:
dt:has(+ dt)
That makes it possible to style the first element based on a sibling that comes after it—something ordinary CSS selectors could not previously do.
Finding sections without a heading
Combine :has() with :not() to find sections missing the expected heading elements:
section:not(:has(heading-display, heading-section, heading-card, heading-small, h5, h6))
The placement of :not() changes the meaning. This version is not equivalent:
section:has(:not(heading-display, heading-section, heading-card, heading-small, h5, h6))
It matches a section containing any descendant that is not one of those headings, which will be most non-empty sections. Parentheses are doing quite a lot of work here.
Browser support changed after publication
When this article was published in December 2021, Safari Technology Preview 137 had enabled :has() by default, Chromium was still implementing it, and Firefox did not support it. Browser support later improved, so check current compatibility before deciding whether a fallback is needed.
:has() removes JavaScript from several small conditional styling jobs. I would keep the selector focused, though; a readable parent rule is useful, while a long chain of nested conditions becomes difficult to understand surprisingly quickly.
Enjoyed reading this?
If you found this article helpful, consider supporting my writing. Every little bit helps keep this blog going.
Related articles
- Making Links Easy to Recognize
Make links recognisable with underlines, clear focus states, useful text, and behaviour that does not surprise the reader.
- When CSS Layout Order Stops Matching the HTML
Keep Grid and Flexbox layouts aligned with the HTML order so keyboard focus and screen reader reading do not jump around the page.
- Keyboard Focus Styles With :focus-visible
Keep a clear keyboard focus indicator while avoiding the same focus ring after every pointer interaction.