: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. This is 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, and your progress syncs across the web and the CoddyKit app. The CSS Academy course includes 4 lessons in total.
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.
Learn CSS with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 40
- Lessons
- 159
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. 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. The CSS Academy course includes 4 lessons in total.
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, so you can start here or from the beginning and move at your own pace. This is lesson 2 of 4.
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