:has()
The Parent Selector
CSS never had a way to select an element by what's inside it, so something like ‘style this card differently if it contains an invalid input’ meant JavaScript. :has() matches an element if any of its descendants match the selector you pass it.
The CSS
.list {
border: 1px solid var(--border);
/* at least one child checkbox is checked */
&:has(input:checked) {
border-color: var(--accent);
}
/* no child is left unchecked, i.e. everything is done */
&:not(:has(input:not(:checked))) {
border-color: var(--success);
}
}
.item:has(input:checked) {
opacity: 0.55;
& span {
text-decoration: line-through;
}
}How it works
Check an item and its row styles itself through .item:has(input:checked), with no handler toggling a class. The container goes further: :has(input:checked) nudges its border toward the accent as soon as one box is ticked, and :not(:has(input:not(:checked))), or “no child is left unchecked”, flips it to green once they all are.
That last rule is the fun one. Composing :not() and :has() gets you “all of these match” even though CSS has no every() selector.
turns, wins and reset, all CSS
trigonometry, in CSS
switch guests on