Syntax
:has(selector)Examples
Styling a Parent Based on Its Children
Highlighting a form group only if it contains an invalid input.
.form-group:has(input:invalid) {
border-left: 3px solid red;
background: #fef2f2;
}Conditional Layout Based on Content
Changing a card's layout depending on whether it contains an image.
.card:has(img) {
grid-template-columns: 100px 1fr; /* image + text layout */
}
.card:not(:has(img)) {
grid-template-columns: 1fr; /* text-only layout */
}Sibling-Based Styling
A powerful combination: styling an element based on the state of a sibling.
.field:has(+ .error-message) input {
border-color: red; /* highlights an input if an error message follows it */
}Parameters and values
- :has(selector) (pseudo-class): Matches if the given selector matches anything inside the element
Best practices
- Use :has() to replace many patterns that previously required JavaScript, like styling a form field based on its own validity state
- Combine :has() with :not() to style elements that specifically lack certain children
- Keep :has() selectors reasonably simple - deeply nested conditions can become hard to reason about, even though they are valid
- Use :has() for genuinely conditional styling based on content structure, not as a general replacement for simple class-based styling
At a glance
- Purpose
- Presentation and layout
- File extension
- .css
- Runs in
- Web browsers
- Usually used with
- HTML and JavaScript
Specifications & further reading
Related CSS documentation
Basic Selectors
CSS selectors target elements to style. Type selectors match by tag name, class selectors (.name) match elements with that class, ID selectors (#name) match a single unique element, and the universal selector (*) matches everything. Classes are the most commonly used selector for reusable styling.Combinators
Combinators define relationships between selectors. The descendant combinator (space) matches any nested element. The child combinator (>) matches only direct children. The adjacent sibling combinator (+) matches the very next sibling. The general sibling combinator (~) matches all following siblings.Attribute Selectors
Attribute selectors target elements based on the presence or value of an HTML attribute, using square bracket syntax. They support several matching modes beyond exact equality, including starts-with, ends-with, and contains, making them powerful for targeting elements without needing extra classes.:is() and :where()
:is() and :where() both accept a list of selectors and match any of them, letting you write more compact selector groups. The key difference is specificity: :is() takes on the specificity of its most specific argument, while :where() always contributes zero specificity, making its rules trivially easy to override.
CSS selectors target elements to style. Type selectors match by tag name, class selectors (.name) match elements with that class, ID selectors (#name) match a single unique element, and the universal selector (*) matches everything. Classes are the most commonly used selector for reusable styling.Combinators
Combinators define relationships between selectors. The descendant combinator (space) matches any nested element. The child combinator (>) matches only direct children. The adjacent sibling combinator (+) matches the very next sibling. The general sibling combinator (~) matches all following siblings.Attribute Selectors
Attribute selectors target elements based on the presence or value of an HTML attribute, using square bracket syntax. They support several matching modes beyond exact equality, including starts-with, ends-with, and contains, making them powerful for targeting elements without needing extra classes.:is() and :where()
:is() and :where() both accept a list of selectors and match any of them, letting you write more compact selector groups. The key difference is specificity: :is() takes on the specificity of its most specific argument, while :where() always contributes zero specificity, making its rules trivially easy to override.