CSS2 min read
CSS :has() Changes Everything
The parent selector we've wanted for 20 years
S
Shahar Amir
CSS :has() Changes Everything
For 20 years, we couldn't style parents based on children. Now we can.
The Problem (Before :has)
Style a card differently if it has an image? Impossible in CSS.
javascript
1234
// Had to use JavaScriptif (card.querySelector('img')) { card.classList.add('has-image');}The Solution: :has()
css
12345678910
/* Style card when it contains an image */.card:has(img) { display: grid; grid-template-columns: 200px 1fr;}
/* No image? Different layout */.card:not(:has(img)) { padding: 1rem;}Basic Syntax
css
12345678
/* Parent that has a child */.parent:has(.child) { }
/* Parent that has a direct child */.parent:has(> .child) { }
/* Parent that has a checked input */form:has(input:checked) { }Practical Examples
Form Validation
css
123456789
/* Highlight field group with error */.field:has(input:invalid) { border-left: 3px solid red;}
/* Show success when valid */.field:has(input:valid:not(:placeholder-shown)) { border-left: 3px solid green;}Image Cards
css
12345678910
/* Card with image: side-by-side layout */.card:has(img) { display: flex; gap: 1rem;}
.card:has(img) img { width: 40%; object-fit: cover;}Navigation State
css
1234
/* Highlight nav item with active link */nav li:has(a[aria-current="page"]) { background: var(--accent);}Dark Mode Toggle
css
12345
/* If toggle is checked, dark mode */body:has(#dark-mode:checked) { background: #1a1a1a; color: white;}Required Field Labels
css
12345
/* Add asterisk to labels of required fields */label:has(+ input:required)::after { content: " *"; color: red;}Advanced: Quantity Queries
css
12345678910
/* Grid when 3+ items */.container:has(:nth-child(3)) { display: grid; grid-template-columns: repeat(3, 1fr);}
/* Single column when less than 3 */.container:not(:has(:nth-child(3))) { max-width: 500px;}Combining with Other Selectors
css
12345678
/* Parent that has both */.card:has(img):has(h2) { }
/* Parent that has either */.card:has(img, video) { }
/* Sibling of element that has */.card:has(img) + .card { }Browser Support
All modern browsers. Use with progressive enhancement:
css
1234567891011
/* Fallback */.card { display: block;}
/* Enhanced experience */@supports selector(:has(*)) { .card:has(img) { display: grid; }}The Power
:has() is essentially a parent selector AND more. You can select any element based on what's inside it or around it. CSS finally caught up to what we needed.
#selectors#modern-css#parent
Stay Updated 📬
Get the latest tips and tutorials delivered to your inbox. No spam, unsubscribe anytime.