CSS :has(): The Game-Changing Selector
CSS :has() — The Parent Selector That Changes Everything
CSS :has(): The Game-Changing Selector

CSS :has() — The Parent Selector That Changes Everything
For years, front-end developers have wished for a way to select a parent element based on its children in CSS. We often resorted to JavaScript or overly complex markup to solve this.
Enter **:has(), a CSS relational pseudo-class that finally makes this possible. With :has(), CSS can look inside elements and apply styles conditionally** based on what they contain. This opens up a whole new world of styling possibilities that were previously impossible.
What is :has()?
The :has() pseudo-class matches elements that contain (or are related to) elements inside the parentheses.
Syntax
selector:has(child-selector) {
property: value;
}
It reads like:
“Select any
selectorthat has achild-selectorinside it.
Basic Examples
1. Style a parent <div> if it has an <img>
div:has(img) {
border: 2px solid green;
}
👉 Any <div> containing an image will get a green border.
2. Highlight a card only if it contains a button
.card:has(button) {
background: #f9f9f9;
}
👉 Useful for feature cards or product blocks where call-to-action buttons are optional.
3. Active navigation item
nav li:has(a.active) {
font-weight: bold;
color: blue;
}
👉 No extra .active class needed on <li>. The parent <li> inherits style when its child <a> is active.
4. Conditional sibling styling
h2:has(+ p) {
margin-bottom: 0;
}
👉 If an <h2> is immediately followed by a <p>, we remove the bottom margin. A small but powerful touch for better typography.
Real-World Use Cases
1. Forms & Validation
.form-group:has(input:invalid) {
border: 1px solid red;
background: #ffeeee;
}
👉 Entire form groups highlight if any contained input is invalid.
2. Media Cards
.card:has(:is(img, video)) {
border: 2px solid #333;
}
👉 Any card that contains media (image or video) gets a styled border.
3. Accordion or Dropdown States
.accordion:has(.accordion-content[open]) {
background: #f1f1f1;
}
👉 The accordion container changes appearance when its content is expanded.
4. Shopping Cart Example
.cart:has(.item) {
border: 2px solid #0073e6;
}
.cart:not(:has(.item)) {
opacity: 0.6;
}
👉 Cart looks active only if it has items, and visually faded if empty — all with pure CSS.
Combining :has() with Other Pseudo-Classes
The real magic happens when :has() works together with :is(), :not(), or :where().
Example — Active Navigation Highlight
.nav-item:has(> a:is(.active, .current)) {
background: #0073e6;
color: white;
}
Example — Exclude Specific Elements
section:has(h2):not(:has(img)) {
padding: 2rem;
background: #fafafa;
}
👉 Sections with headings but no images get a neutral background.
Browser Support
- ✅ Chrome 105+
- ✅ Safari 15.4+
- ✅ Edge 105+
- ⚠️ Firefox — still behind a flag as of 2025
Before using :has() in production, check if your user base relies heavily on Firefox.
Why :has() Matters
- Less JavaScript: Many DOM-manipulation use cases can now be solved directly in CSS.
- Cleaner Markup: No need to add redundant parent classes.
- More Expressive CSS: You can finally write “if/else” style conditions.
It feels like CSS has stepped into the world of logic — without losing its declarative nature.
Final Thoughts
The :has() pseudo-class is a game-changer for CSS. It brings flexibility, reduces reliance on JavaScript, and empowers developers to write smarter, more intuitive styles.
If you haven’t tried it yet, start experimenting with :has() in small UI components like cards, navigation menus, or form validation. Once you see how powerful it is, you’ll never want to go back.
메타데이터
- post_id
- 93e52327cd3c
- slug
- css-has-the-game-changing-selector-93e52327cd3c
- url
- https://medium.com/@uxuip29/css-has-the-game-changing-selector-93e52327cd3c
- canonical_url
- https://medium.com/@uxuip29/css-has-the-game-changing-selector-93e52327cd3c
- author_url
- https://medium.com/@uxuip29
- status
- ok
- fetched_at
- 2026-06-24 11:06:28