Question
How can I select the <li> element that is the direct parent of an anchor element in CSS?
For example, I would like to write something like this:
li < a.active {
property: value;
}
I understand this can be done with JavaScript, but I want to know whether there is a native CSS solution, especially in CSS Level 2.
In my case, the menu HTML is generated by a CMS, so I cannot easily move the active class from the <a> element to the <li> element unless I customize the menu generation code, which I would prefer to avoid.
Short Answer
By the end of this page, you will understand why older CSS could not select a parent element from a child, what a CSS parent selector really means, how the modern :has() pseudo-class solves this problem, and what alternatives developers used before :has() was available.
Concept
In CSS, selectors traditionally work from left to right by matching the final element, even though browsers may optimize internally. In practical terms, classic CSS was designed mainly to style an element based on:
- its own type, class, or ID
- its attributes
- its ancestors
- its siblings
What it could not do in CSS Level 2 or most of CSS Level 3 was select an element based on one of its children or descendants. That missing feature is what developers often call a parent selector.
In your example, you want to style this parent element:
<li>
<a class="active" href="/home">Home</a>
</li>
based on the fact that it contains an <a> with class active.
Older CSS had no selector for this. So in CSS Level 2, the answer was effectively no, there is no parent selector.
Modern CSS now provides a way to do this using the :has() pseudo-class:
li:has(> a.active) {
property: value;
}
Mental Model
Think of classic CSS like reading a family tree only downward:
- You can style a child because it lives inside a parent.
- You can style a descendant because it lives inside an ancestor.
- But you could not go backward and say, "Style the parent because one child has a special badge."
That is exactly what a parent selector would do.
A simple analogy:
- Old CSS: "Choose the person wearing the red shirt."
- Parent selector: "Choose the parent of the person wearing the red shirt."
Classic CSS could identify the child, but not climb back up to style the parent.
Modern :has() works like a rule that says:
- "Select any folder that contains a file named
active."
So li:has(> a.active) means:
- select the
li - if inside it there is a direct child anchor with the class
active
Syntax and Examples
Core syntax
Modern CSS uses :has() for parent-like selection.
li:has(> a.active) {
color: red;
}
This selects an li if it has a direct child matching a.active.
Example HTML
<ul>
<li><a href="/home">Home</a></li>
<li><a href="/about" class="active">About</a></li>
<li><a href="/contact">Contact</a>
Step by Step Execution
Consider this HTML:
<ul>
<li><a href="/home">Home</a></li>
<li><a href="/about" class="active">About</a></li>
</ul>
And this CSS:
li:has(> a.active) {
background: gold;
}
Here is what happens conceptually:
- CSS looks at each
lielement. - For the first
li, it checks whether it has a direct child matchinga.active. - The first
licontains<a href="/home">Home</a>, which does have class .
Real World Use Cases
Parent-like selectors are useful in many real projects.
Navigation menus
A CMS may mark the current page like this:
<li><a class="active" href="/products">Products</a></li>
You may want the entire menu item highlighted, not just the link text.
Form validation
Style a wrapper if it contains an invalid field:
.field:has(input:invalid) {
border-color: red;
}
Cards with special content
Highlight a product card if it contains a sale badge:
.card:has(.sale-badge) {
box-shadow: 0 0 0 2px orange;
}
Tables and lists
Style rows that contain selected checkboxes:
Real Codebase Usage
In real codebases, developers usually choose among a few patterns depending on control over the markup and browser support needs.
1. Best when you control the HTML: put state on the element you want to style
<li class="active"><a href="/about">About</a></li>
li.active {
font-weight: bold;
}
This is simple, clear, and usually best for maintainability.
2. Use :has() when markup cannot be changed
.nav-item:has(> a.active) {
background: #eef;
}
This is common in CMS-driven layouts and reusable components.
3. Use JavaScript as a fallback when needed
If browser support requirements prevent using :has() alone, developers may add classes at runtime:
Common Mistakes
1. Expecting old CSS to support parent selection
This does not work in CSS Level 2:
li < a.active {
color: red;
}
There is no < parent selector in CSS.
2. Styling the child when you meant to style the parent
This styles the anchor, not the li:
a.active {
background: yellow;
}
If you want the parent, use:
li:has(> a.active) {
background: yellow;
}
3. Forgetting the difference between direct child and any descendant
This matches only direct children:
li:has(> a.active) {}
This matches any nested descendant:
Comparisons
| Approach | Can style parent based on child? | Works in old CSS? | Best use case |
|---|---|---|---|
a.active | No | Yes | Style the link itself |
li.active | Yes, if class is already on parent | Yes | Best when you control HTML |
li:has(> a.active) | Yes | No | Best modern CSS solution |
| JavaScript adds class to parent | Yes | Yes, with JS enabled | Fallback for unsupported environments |
:has() vs adding a class to the parent
| Option |
|---|
Cheat Sheet
/* Style the link itself */
a.active {
color: red;
}
/* Style the li if it has a direct child anchor with class active */
li:has(> a.active) {
color: red;
}
/* Style the li if it has any descendant anchor with class active */
li:has(a.active) {
color: red;
}
Key rules
- CSS Level 2 had no parent selector.
- The old attempted syntax
li < a.activeis invalid. - Modern CSS uses
:has()for parent-like matching. >means direct child.- No
>means any descendant. - If you control the HTML, putting the class on the parent is often the cleanest solution.
Quick decision guide
- Need old-browser-friendly CSS only? Put the class on the parent if possible.
- Cannot change markup and can use modern CSS? Use
:has(). - Need legacy support and cannot change markup? Use JavaScript to add a parent class.
Common pattern
FAQ
Is there a parent selector in CSS Level 2?
No. CSS Level 2 does not support selecting a parent based on a child element.
How do I select a parent <li> when the <a> has class active?
In modern CSS, use:
li:has(> a.active) {}
What does :has() do in CSS?
It matches an element if that element contains something matching the selector inside :has().
Can I use li < a.active in CSS?
No. That is not valid CSS syntax.
What if I need to support older browsers?
Use one of these approaches:
- add the class to the parent in the HTML
- use JavaScript to add a class to the parent
- adjust your CMS template output
Is :has() a true parent selector?
People often call it that, but technically it is a relational pseudo-class that lets you match an element based on its descendants or related elements.
Should I use :has() or add a class to the parent?
Mini Project
Description
Build a small navigation menu where the active page link is marked on the <a> element, and style the parent <li> based on that child state. This mirrors a common CMS or framework scenario where you cannot change the generated HTML easily.
Goal
Create a menu that highlights the entire list item when its child link has the active class.
Requirements
- Create an unordered list with at least three menu items.
- Put the
activeclass on one<a>element, not on the<li>. - Use CSS to style the parent
<li>of the active link. - Add at least two visible styles, such as background color and bold text.
Keep learning
Related questions
CSS Font Scaling Relative to Container Size: %, em, rem, vw, and Responsive Text
Learn how CSS font scaling really works and how to make text responsive using %, em, rem, vw, clamp(), and media queries.
CSS Previous Sibling Selector: What Exists and How to Work Around It
Learn whether CSS has a previous sibling selector, why it does not, and practical ways to style earlier elements using CSS alternatives.
CSS Transitions on display: Why They Don't Work and How to Fade Elements In
Learn why CSS cannot transition the display property and how to create smooth fade-in dropdown menus using opacity and visibility.