
Conditional Parent Styling with the CSS has Relational Pseudo-Class
For twenty-five years, CSS was strictly unidirectional: selectors could query children from parents, but could never style a parent based on the state or existence of a child. Developers were forced to attach JavaScript event listeners to toggle .has-error or .is-active classes on parent containers.
The CSS :has() pseudo-class—often called the "parent selector"—enables relational queries in pure CSS.
Example
Styling a card container differently when it contains a featured image, or highlighting a form fieldset when an input inside it is invalid:
/* Style parent article when it contains an image */
.article-card:has(img) {
grid-template-columns: 200px 1fr;
}
/* Highlight form fieldset when any required child is empty or invalid */
.form-section:has(input:invalid:focus) {
border-color: var(--darkred);
box-shadow: 0 0 0 3px rgba(197, 0, 74, 0.15);
}
Implementation
/* Style previous siblings: highlight preceding list item on hover */
li:has(+ li:hover) {
opacity: 0.7;
}
Main Point: :has() eliminates dozens of lines of DOM-toggling JavaScript by allowing parent and sibling styles to react dynamically to child states in pure CSS.
Credits
Photo by Luca Bravo on Unsplash