:has() Relational Pseudo-class
Select parent elements based on their children using the powerful :has() relational pseudo-class.
:has() Relational Pseudo-class is a free CSS Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the CSS Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What is :has()?
The :has() pseudo-class selects an element if it contains a descendant matching the argument. Often called the "parent selector," it enables styling a parent element based on its children — a capability CSS never had before.
Basic Syntax
.card:has(img) selects any .card element that contains an img descendant. The argument is a relative selector list — any valid CSS selector describing elements relative to the subject element.
Styling Parents
Style a form container when it has an invalid input: form:has(:invalid) { border-color: red; }. Style a section that contains a heading: section:has(h2) { padding-top: 2rem; }. The parent changes appearance based on child state.
Sibling Selection
:has() can select preceding siblings — something + and ~ cannot do. h2:has(+ p) selects h2 elements immediately followed by p. li:has(~ .active) selects li elements that have a subsequent .active sibling.
Form State Styling
React to native form validity without JavaScript: input:has(~ .error-msg) styles an input with a sibling error message. label:has(+ input:required) styles labels whose paired input is required — all from CSS alone.
Navigation State
Highlight navigation containers based on active child: nav:has(.active) applies styles to the entire nav when any child has the active class. Useful for indicating which navigation section is current at the container level.
Combining with Other Pseudo-classes
.grid:has(.card:focus-within) styles the entire grid when any card receives keyboard focus. .dropdown:has(:hover) keeps a dropdown open while hovering any descendant — cleaner than complex sibling combinator chains.
Media Query Equivalent in CSS
.sidebar:has(nav) applied different layout than .sidebar:not(:has(nav)). Conditional layout without JavaScript: the presence or absence of specific children drives the parent's layout — enabling truly adaptive, content-aware CSS.
Performance Considerations
:has() with broad argument selectors (e.g., :has(*)) can be expensive — the browser must check every element. Keep :has() arguments specific. Prefer :has(> .specific-child) (direct child) over :has(.specific-child) (any descendant) when possible.
Browser Support
:has() is supported in Chrome 105+, Safari 15.4+, Firefox 121+. Full baseline support since late 2023. No polyfill exists (it would require JavaScript to simulate) — use it with progressive enhancement for older browsers where the feature is non-critical.
Replacing JavaScript Patterns
Patterns previously requiring JS event listeners: "add class to parent when child is focused," "show overlay when modal-trigger exists," "style a grid differently when it has exactly three items." :has() handles all of these declaratively.
Knowledge Check
What makes :has() unique compared to existing CSS combinators like + and ~?
Summary
:has() is CSS's first true relational pseudo-class that enables parent and preceding-sibling selection. It powers content-driven styling, form state reactions, navigation highlighting, and many patterns that previously required JavaScript DOM manipulation — all declaratively in CSS.
Frequently asked questions
Is the “:has() Relational Pseudo-class” lesson free?
Yes — the full text of “:has() Relational Pseudo-class” is free to read here on the web, and the CSS Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the CSS Academy course, upgrade to CoddyKit PRO.
What will I learn in “:has() Relational Pseudo-class”?
Select parent elements based on their children using the powerful :has() relational pseudo-class. You practise CSS Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start CSS Academy?
No prior experience is required. CSS Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “:has() Relational Pseudo-class” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this CSS Academy lesson?
Yes. Every CSS Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Native CSS Nesting
- :has() Relational Pseudo-class
- @scope for Scoped Styles
- View Transitions API