Clean Markup

Conditional Parent Styling with the CSS has Relational Pseudo-Class

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

← Home