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.
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
Related Topics
CSS :has() Selector — Parent Selector + 8 Examples | Free, In-Browser
Pseudo-classes
CSS :is() Grouping Selector - Combine Selector Lists Cleanly
Pseudo-classes
CSS :where() Zero Specificity - Build Easy-to-Override Defaults
Pseudo-classes
CSS Form Validation Selectors - :valid, :invalid, :required
UI State