CSS :has() Parent Selection - Style Parents Based on Children

Use the CSS :has() relational pseudo-class to select parent elements based on their children. Real-world layout patterns, conditional card styling, and form group examples.

Pseudo-classes

Detailed Explanation

Selecting Parents With :has()

Before :has(), CSS could only flow downward — a parent could not be styled based on the content of its children without JavaScript. The :has() pseudo-class flips this entirely: any element that contains a matching descendant becomes selectable.

Conditional Layout Switching

A common pattern is changing a wrapper's layout when it contains a particular child:

/* Cards with media use a horizontal split */
.card:has(> figure) {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 16px;
}

/* Cards without media stack normally */
.card:not(:has(> figure)) {
  padding: 24px;
}

Parent Form Group Validation

Coloring the entire field row when an input becomes invalid keeps the markup clean:

.field:has(input:user-invalid) {
  background: rgba(239, 68, 68, 0.05);
  border-color: rgb(239, 68, 68);
}

.field:has(input:focus) label {
  color: var(--accent);
}

Counting Children Reactively

Combine :has() with :nth-child to detect how many items live inside a list:

/* Switch to two-column layout once a 5th item appears */
.gallery:has(> :nth-child(5)) {
  columns: 2;
}

Scope and Specificity

The selector inside :has() is evaluated in the scope of the element it's attached to. Specificity follows the same rule as :is(): it equals the highest-specificity selector inside the parentheses. So a:has(.icon) has the same specificity as a.icon would have if they were siblings — one type plus one class.

Fallback Strategy

:has() is unsupported in older Firefox releases (pre-121). Use @supports selector(:has(*)) to opt in only when available so legacy browsers receive a sane baseline first.

Use Case

Use :has() when a parent's appearance depends on what's inside it: gallery wrappers that adapt when a video child is present, form rows that turn red on invalid fields, or sticky headers that grow shadows once a sibling scrolls past them. It removes a huge category of small JavaScript helpers.

Try It — CSS Selector Reference

Open full tool