For most of the history of CSS, selectors have been limited to targeting elements based on their parents in the DOM tree. Consider this HTML structure:
<div>
<p>Paragraph 1</p>
<div>
<main>
<div>
<p>Paragraph 2</p>
</div>
<main>
Applying styles to paragraph 2 in CSS is trivial, as it can be targeted by the parent <main> node.
main p {
color: blue;
}
This will style Paragraph 2 but not Paragraph 1, as the second paragraph is contained inside the <main> element.
What has not historically been simple however, was styling the <main> node based on the presence of the <p> tag below it.
<main>
Don't Style This
</main>
<main>
<p>Style This</p>
</main>
By looking upwards in the DOM tree, there was no way to apply styles to just the second <main> element and not the first (without uses classes or IDs of course).
Introducing the :has() Selector
At its core, the :has() selector is a relational pseudo-class. This means it allows you to select an element based on its relationship with other elements. Specifically, it selects an element if it contains another element that matches a given selector.
In the above example, we can now do the following:
main:has(p) {
color: red;
}
This opens up numerous possibilities for styling your web pages more efficiently and with less code.
Example 1 – Highlighting Articles with Images
Consider a webpage that displays a list of articles, each enclosed in an <article> tag. If we want to highlight articles that contain images, the :has() selector offers a straightforward solution:
article:has(img) {
border: 2px solid red;
}
Example 2 - Styling Navigation Menus with Sub-Menus
.main-menu > li:has(.sub-menu):before {content: "▼";margin-left: 5px;font-size: 0.75em;}
0 Comments: