Skip to content
tezvyn:

CSS :has(): Query Parents and Previous Siblings

Source: developer.mozilla.orgMediumHow cards are made

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.

Interview question

In the rule section:has(.featured) { border: 2px solid blue; }, which element actually receives the blue border?

  • a.The element with class featured
  • b.The featured element and its parent section
  • c.Any section containing a descendant with class featuredCorrect
  • d.Every descendant inside a section that has a featured child
Why?

:has() is a conditional self-query that styles the anchor element—the section—when the argument matches a descendant or sibling. Option A is tempting because it looks like the selector inside the parentheses is the target, but .featured is only the condition being checked, not the element that gets styled.

Just read this? Test yourself on what you have been reading.

Read the original → developer.mozilla.org

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on css — each one lists the topics its interview covers.

See open roles