:has() can style a parent based on its children, a sibling based on its brother, and a form based on its own validation state. According to caniuse it is supported by 95.91 percent of browsers today, which is more than support some CSS you learned years ago. Here are seven recipes that used to need JavaScript.
1. Highlight the card that contains an invalid input
.card:has(input:user-invalid) {
outline: 2px solid var(--tomato);
}2. Style every checkbox row consistently from the checkbox itself:
li:has(> input:checked) {
text-decoration: line-through;
}3. A header that leaves space for the sidebar, only when the sidebar is present:
body:has(.sidebar) .header {
padding-left: 18rem;
}4. Figures with no caption get no drop shadow. Their cousins keep it:
figure:not(:has(figcaption)) img { box-shadow: none; }5. Grid columns that adapt to what was dropped into the list. gacor for CMS content:
.grid:has(> :nth-child(3)) { grid-template-columns: repeat(3, 1fr); }6. Open state styling without a JS toggle, using the popover attribute:
body:has(#search[open]) { overflow: hidden; }7. Article text with at least one code block gets wider measure:
article:has(pre) { max-width: 72ch; }Deleting a DOM script is a nicer refactor than most refactors get to be.
Firefox has supported it since v121, so the old catch-up list of browser excuses is finally empty. Delete the script tag and let the selector do the work. If you want the layout cousin of this trick, read container queries next.
