tezvyn:

CSS :has(): Query Parents and Previous Siblings

AI-drafted, machine-checkedSource: developer.mozilla.orgintermediate
CSS :has(): Query Parents and Previous Siblings

CSS :has() styles an element based on its children or later siblings, like highlighting a section with a featured card. Previously this required JavaScript. If unsupported, the whole selector block fails, so wrap it in :is() or use progressive enhancement.

WHY IT EXISTS: CSS selectors have always flowed downward and forward: you style descendants and later siblings, but never parents or previous elements. This forced developers to add extra classes in HTML or reach for JavaScript just to style a container based on its contents. The :has() pseudo-class closes this gap by allowing an element to query its own tree in reverse: it matches the anchor element when any relative selector passed as an argument finds a match inside or after it.

THE MENTAL MODEL: Think of :has() as a conditional self-query. Instead of asking which children match this rule, you ask do I contain or precede something that matches? If the answer is yes, the anchor element itself gets styled. It is the CSS equivalent of looking over your shoulder before deciding what to wear.

HOW IT WORKS: You pass :has() a relative selector list. The browser anchors each selector against the element in question and checks for matches. For parent checks, write section:has(.featured) to target any section containing an element with class featured, or section:has(> .featured) to require a direct child. For sibling checks, h1:has(+ p) targets an h1 only when a paragraph immediately follows it. Specificity follows the most specific selector inside the argument, behaving like :is() and :not(). However, :has() cannot be nested inside another :has(), and pseudo-elements are invalid both inside and as anchors for :has() because they could create cyclic styling dependencies.

WHEN TO USE IT: Use :has() when container styling should react to content without changing markup. Common cases include highlighting a card grid when it contains a promoted item, adjusting heading margins based on the next element, or applying special layouts to forms that contain specific input types. It shines in design systems where markup patterns are consistent but content varies.

WHEN NOT TO USE IT: Avoid :has() when you need guaranteed support in older browsers, because if :has() itself is unsupported the entire selector block is discarded. Do not use it for heavy document-wide queries that could force expensive reflows, and never nest :has() within :has(). If you need to style pseudo-elements conditionally, use a class-based approach instead.

ONE CANONICAL EXAMPLE: A section should gain a blue border only when it contains a featured article. The HTML has two section elements, one with an article class of featured and one without. The rule section:has(.featured) { border: 2px solid blue; } applies the border only to the first section, leaving the second untouched. No extra classes on the parent and no JavaScript required.

Source: developer.mozilla.org

Read the original → developer.mozilla.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.