The has() Selector Explained
- CSS Basics
- Selectors & Specificity
- Box Model & Units
- Typography & Text Styling
- Colors & Color Spaces
- Positioning & Stacking Context
- Flexbox
- Grid
- Grid Advanced
- Responsive Design
- Container Queries
- Pseudo-classes & Pseudo-elements
- Modern Selectors
- CSS Custom Properties
- CSS Functions
- Transitions & Animations
- Transforms
- Forms & Input Styling
- CSS Architecture & Methodologies
- Accessibility in CSS
- Performance & Optimization
- View Transitions & Modern APIs
- Cascade Layers & Scope
The Gap :has() Fills
CSS has always been able to select a child based on its parent, but never the reverse - there was no way to style a parent based on what it contains. :has() is often described as the long-awaited "parent selector."
Basic Usage
.card:has(img) {
padding: 0; /* cards with an image get no padding */
}This styles a .card element differently depending on whether it happens to contain an <img> - something that was impossible in CSS before :has().
Styling a Container Based on an Input's State
.form-group:has(input:invalid) {
border-left: 3px solid red;
}
.form-group:has(input:focus) {
background: #f0f7ff;
}This lets a wrapping element react to the validation or focus state of an input inside it, without needing any JavaScript to add or remove a class manually.
Combining with Sibling Selectors
h2:has(+ p) {
margin-bottom: 0.5em; /* only if a paragraph immediately follows */
}Common Practical Uses
- Styling a form field's wrapper based on validation state.
- Adjusting a card's layout depending on whether it contains an image, video, or just text.
- Highlighting a table row that contains a specific status cell.
A Note on Performance
:has() is powerful, but checking a subtree for a condition is inherently more work for the browser than a simple selector. It performs well for typical use cases, but is not a reason to avoid state classes entirely in performance-critical, deeply nested structures.