Selector pseudo-class :has()

The functional :has() CSS pseudo-class represents
an element if any of the relative selectors that
are passed as an argument match at least one
element when anchored against this element. This
pseudo-class presents a way of selecting a parent
element or a previous sibling element with respect
to a reference element by taking a relative
selector list as an argument.

Logical operators with CSS :has

/* OR */
.shelf:has(.bookPurple, .bookYellow) {
  outline: dashed 2px deeppink;
}

/* AND */
.shelf:has(.bookPurple):has(.bookYellow) {
  outline: dashed 2px deeppink;
}

Card with hovered button

.card:has(.button:hover) {
  box-shadow:
    0 2px 4px 0 rgba(#000, 0.15),
    0 3px 25px 0 rgba(#000, 0.15);
}

.card {
  &:has(.button:hover) {
    color: #fff;
    background-color: var(--brand-1);
    box-shadow:
      0 0 0 7px var(--brand-1),
      0 2px 20px 0 rgba(#000, 0.25),
      0 3px 45px 0 rgba(#000, 0.25);

    .button {
      color: inherit;
    }

    h3,
    p {
      color: inherit;
    }
  }
}

Dual hover with data attributes and :has



<div class="wrapper">
  <ul class="tags">
    <li data-name="css">CSS</li>
    <li data-name="design">Design</li>
  </ul>

  <div>
    <article data-name="css"></article>
    <article data-name="design"></article>
  </div>
</div>
.wrapper:has([data-name="css"]:hover) [data-name="css"] {
  outline: 2px solid;
}

Dynamic menu layout with quantity queries

/* 6+ items */
.submenu:has(li:nth-last-child(n + 6)) {
  display: grid;
  grid-template-columns: 1fr 1fr;
  width: 250px;
}

/* 8+ items */
.submenu:has(li:nth-last-child(n + 8)) {
  grid-template-columns: 1fr 1fr 1fr;
  width: 350px;
}

Examples

/* Selects an h1 heading with a
paragraph element that immediately follows
the h1 and applies the style to h1 */
h1:has(+ p) {
  margin-bottom: 0;
}

h1,
h2 {
  margin: 0 0 1rem 0;
}

h1:has(+ h2) {
  margin: 0 0 0.25rem 0;
}

h1,
h2,
h3 {
  margin: 0 0 1rem 0;
}

:is(h1, h2, h3):has(+ :is(h2, h3, h4)) {
  margin: 0 0 0.25rem 0;
}

:is(h1, h2, h3):has(+ h2, + h3, + h4) {
  margin: 0 0 0.25rem 0;
}

body:has(video, audio) {
  /* styles to apply if the content contains audio OR video */
}
body:has(video):has(audio) {
  /* styles to apply if the content contains both audio AND video */
}