has() selector
⚡ TL;DR
A new, very powerful, CSS selector, opening previously impossible selectors without either CSS pre-processor or JS:
- parent selector (style ancestors based on their children)
- previous sibling
- cousins (style elements based on some other element with a common ancestor but not siblings)
🧪 Experiment
❌ Your browser does NOT support the feature tested below. Try another browser
#1 - Modify a parent selector
Example: theme toggle with no js
We'll modify global values (<body> colors) based on the state of an input low down the DOM tree (the <checkbox> `checked`)
<label for='dark-theme-toggle'>
<span class='dark-theme'>Activate dark theme🌙</span>
<input
id='dark-theme-toggle'
type='checkbox'
aria-label='active-dark-theme'
/>
</label>
body:has(#dark-theme-toggle:checked) {
--bg-primary: #000;
--txt-primary: #fff;
}
#2 - Modify a consin
<common ancestor element>
<a div element>
<cousin element earlier in the DOM tree>
<another div element>
<cousin element later in the DOM tree>
<div class='common-ancestor'>common ancestor element
<div>a div element
<p class='early-cousin'>cousin element earlier in the DOM tree</p>
</div>
<div>another div element
<p class='state-to-check'>cousin element later in the DOM tree</p>
</div>
</div>
.common-ancestor:has(.state-to-check) .early-cousin {
background-color: deeppink;
}
🤔 Opinion
- 🔥 CSS just became a lot easier and fun to use !
- 🧹 we'll be able to remove tons of js
- 🌌 we're probably only grasping the impact this can have on the way we author our UI. Probably one of the most impactful CSS feature of the recent years passed and to come
- 💻 Not usable in production yet because of support, but we should start thinking about how we would already code things differently if we had it, so we mentally start to understand all the possibilities