For years, the answer to "can CSS select a parent based on its children?" was a sad "no, use JavaScript."
Not anymore. :has() is supported in all modern browsers, and it changes how you write CSS. Here are three tricks you can use today.
1. Style a card differently if it contains an image
.card {
display: grid;
gap: 1rem;
}
.card:has(img) {
grid-template-columns: 200px 1fr;
}
No extra classes like .card--with-image. The CSS looks at the content and adapts.
2. Highlight a label when its input is invalid
label:has(+ input:invalid) {
color: crimson;
}
The label turns red when the input right after it fails validation. No JS, no state.
3. A dark mode toggle with zero JavaScript
<input type="checkbox" id="theme" />
<label for="theme">Dark mode</label>
:root {
--bg: #fff;
--fg: #111;
}
:root:has(#theme:checked) {
--bg: #111;
--fg: #eee;
}
body {
background: var(--bg);
color: var(--fg);
}
The checkbox lives anywhere in the page, and :root reacts to it.
Bonus: it works like a "not" too
/* Dim all siblings when one is hovered */
ul:has(li:hover) li:not(:hover) {
opacity: 0.5;
}
Wrap up
:has() lets CSS respond to the content and state of your markup, and that cuts a lot of "toggle a class" JavaScript.
What's the coolest thing you've built with it? Let me know in the comments
Top comments (0)