DEV Community

Cover image for Exploring the :has() CSS Pseudo-Class
Matt Miller
Matt Miller

Posted on

Exploring the :has() CSS Pseudo-Class

Introduction:
In the realm of CSS, the :has() pseudo-class stands out as a powerful selector that enables developers to target elements based on the presence of specific descendants. This pseudo-class offers a flexible and expressive way to style elements based on their contextual relationships within the document structure.

Understanding :has():
The :has() pseudo-class selects an element if any of the relative selectors provided as arguments match at least one element when anchored against the selected element. This means it can target parent elements or previous sibling elements relative to a reference element, enhancing CSS selectors' versatility and capability.

Syntax:
The syntax for the :has() pseudo-class is straightforward:

:has(<relative-selector-list>) {
  /* CSS rules */
}
Enter fullscreen mode Exit fullscreen mode

Here, <relative-selector-list> represents the list of relative selectors used to determine if the element matches the selector.

Behavior and Limitations:

  • The specificity of the :has() pseudo-class matches that of the most specific selector within its arguments, similar to :is() and :not().
  • If :has() is not supported in a browser, the entire selector block will fail unless it's within a forgiving selector list like :is() and :where().
  • :has() cannot be nested within another :has() to prevent cyclic querying.
  • Pseudo-elements are not valid selectors within :has(), and pseudo-elements cannot serve as anchors for :has().

Example:
Consider the following example that adjusts the spacing after <h1> headings if they are immediately followed by an <h2> heading:

<section>
  <article>
    <h1>Morning Times</h1>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
      tempor incididunt ut labore et dolore magna aliqua.
    </p>
  </article>
  <article>
    <h1>Morning Times</h1>
    <h2>Delivering you news every morning</h2>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
      tempor incididunt ut labore et dolore magna aliqua.
    </p>
  </article>
</section>
Enter fullscreen mode Exit fullscreen mode
h1,
h2 {
  margin: 0 0 1rem 0;
}

h1:has(+ h2) {
  margin: 0 0 0.25rem 0;
}
Enter fullscreen mode Exit fullscreen mode

In this example, the margin after <h1> elements is reduced if they are immediately followed by an <h2> element, illustrating the use of :has() to apply styling based on contextual relationships.

Advanced instance

  section:hover:not(:has(*:hover)):not(:focus-visible):not(.selected),
  section *:hover:not(:has(*:hover)):not(:focus-visible):not(.selected) {
    cursor: pointer;
    border-radius: 0.5rem;
    outline: 2px dashed #0092f3;
  }
Enter fullscreen mode Exit fullscreen mode

In this example, the :not() selector plays a key role alongside the :has() selector. Together they will independently select an element.

Conclusion:
The :has() pseudo-class expands the capabilities of CSS selectors, allowing for more precise targeting of elements based on their relationships within the document structure. By understanding its syntax, behavior, and limitations, developers can leverage :has() to craft more sophisticated and context-aware stylesheets, enhancing the presentation and usability of their web projects.

Top comments (0)