Having a “parent selector” in CSS is mentioned regularly as something CSS could really use. I feel like I’ve had that thought plenty of times myself, but then when I ask my brain for a use case, I find it hard to think of one. Well, I just had one so I thought I’d document it here.
A classic parent/child:
<div class="parent">
<div class="child"></div>
</div>
Say it makes a lot of sense for this parent to have hidden overflow and also for the child to use absolute positioning.
.parent {
overflow: hidden;
position: relative;
}
.child {
position: absolute;
}
Now let’s say there’s one special circumstance where the child needs to be positioned outside the parent and still be visible. Hidden overflow is still a good default for the vast majority of situations, so it’s best to leave that rule in place, but in this very specific situation, we need to override that overflow.
.special-child {
position: absolute;
bottom: -20px; /* needs to be slightly outside parent */
}
/* Not real, but just to make a point */
.special-child:parent(.parent) {
overflow: visible;
}
That selector above is fake but it’s saying, “Select the parent of .special-child
,” which would allow that override as needed. Maybe it’s like this:
.parent < .special-child {
}
…which is selecting the element on the left rather than the right. Who knows? Probably both of those are problematic somehow and the final syntax would be something else. Or maybe we’ll never get it. I have no idea. Just documenting a real use case I had.
You might be thinking, “Why not just use another special class on the parent?” I would have, but the parent was being injected by a third-party library through an API that did not offer to add a class of my choosing on it. Ultimately, I did have to add the class to the parent by writing some custom JavaScript that queried the DOM to find the .special-child
, find the parent, then add the class there.
Do y’all have some other use-cases for a parent selector?
Here’s one from Uzair Hayat:
My project has an
<input>
which is wrapped in a<div>
. The<div>
has a few design elements which need to take effect once the<input>
is in:focus
. I could have used::before
and::after
pseudo-elements, but inputs do not support those as they are replaced elements. Right now, I juse JavaScript to detect if the input is in focus and apply a class to the parent div. I wish I could do…
input:focus:parent(div):after {
display: block;
/* display design changes when focused */
}
CSS should have XPath support!
One I ran into today, a collection of radio buttons coded like so:
<label>A choice <input type="radio"></label>
When the user finishes their selections of radio buttons and submits their response, I set the input to disabled:
<label>A choice <input type="radio" disabled="disabled"></label>
It’d be really handy to be able to style the
<label>
based on the presence of thedisabled
attribute.This a good example of how convenient a parent selector would be. However, you can accomplish the task by taking the input out of the label.
You may have already considered this:
`
input[disabled] ~ label {
color: #777;
}
Field Name
`
It may by possible to do what you want with mostly CSS by using a hidden checkbox combined with HTML
id
andfor
label redirection.HTML could look a bit like…
… then style such that the checkbox state effects label via
~
…… For completion a bit of JavaScript to toggle radio state too…
My answer regarding CSS Parent Selectors on StackOverflow, may be worth checking out for other things that checkboxes and labels are capable of.
Couldn’t the label and input be siblings instead?
what about the :has() psuedo class?
https://developer.mozilla.org/en-US/docs/Web/CSS/:has
.parent:has(> .special-child) {}
select parent classes with a direct child of class sepcial-child.
My educated guess is that we’ll gonna see rather syntax similar to
.parent:has-child(.special-child)
.@Joe Maffei
They could be siblings but then you lose the semantics added by the element making the radio selectable by clicking the label as is intentional and the reason for using the label element rather than any other.
This is probably a lot like your use case, but another case for a parent selector would be the container for a specific component in a list of elements that don’t have classes themselves, presumably because you don’t have direct access to the underlying source code. For instance, the main page code might be like this:
A parent selector would be much more convenient there than adding a class via JavaScript, or using div:nth-of-type(3).
And it’d also be less fragile. If they change the order later on so the calendar is now the second block on the page, your original CSS would break. So if you went with the former, you’d have to update it every time the page order changed.
So that’s one use case. Still, I know that people will question it. After all, can’t you just edit the underlying code to add a class to the parent?
Not necessarily. You can if you run the site in question and have server access, but sometimes you’re doing A/B tests for client sites using third party tools (like say, VWO or Target). These give you no access to the source code of the page beyond what can be edited via JavaScript or CSS.
Plus they’re often also targeted on a ‘general’ basis, like ‘run this test on all pages whose URL starts with blog’. Hence targeting these elements with CSS alone is a hassle.
So yeah, I think A/B tests are another good use case for a parent selector, especially when used on sites which don’t give you enough class names to identify a particular element beyond ‘nth-of-type/nth-child’ shenanigans.
Are we talking about a direct parent selector, or a more versatile (but probably more costly in terms of performance) ancestor selector?
Use case for the latter could be preventing body scroll when a modal is open:
Considering that
dialog
elements are probably best placed as direct children of thebody
tag anyway, I guess the above would also work with “just” a direct parent selector, but that’s besides the point.I highly hope such a selector be implemented soon. From what I have experienced, it has more use cases than
:is
.In fact, the working draft already included the relational pseudo-class
:has()
, which can serve the purpose.With
:has()
, the use case’s selector could be written as.parent:has(> .special-child)
.As for now, MDN states that this pseudo-selector can not be used within stylesheets, but only in JS functions like
document.querySelector('div:has(h1)')
. I think it has something to do with the complexity involved in calculating parent selectors live in the page.Most of when I’ve wanted a CSS parent selector is to style HTML I can’t easily edit directly (like output from some WordPress plugins). I’ve occasionally used Javascript to add my own HTML just to have some targets to style where a CSS parent selector would have done wonders!
It hits a point where CSS will start failing the more we ask it to do. From what I read years ago a parent selector is detrimental to how CSS works… by cascading. Not only in the style sheet perspective, but also in the design and document flow.
I feel like if we push for this too hard, we will cause CSS to turn into something ugly and inelegant.
There will always always be limitations in every language. I think we should leave this one as it is.
I only needed a parent selector when I was a newby CSS designer. Try and work around the limitation by evaluating your processes and structures. (you have to anyway because there is no parent selector) and accept that if this is the worst limitation we have in CSS, then it’s really not too bad.
I find myself frequently wishing CSS had a parent selector. Similar to what you described, the software I work with has many elements that get assigned dynamic id’s that can’t be depended upon. In frequently need to style the parent of some element but don’t have an easy way to reference it. I’m forced to either reference it start with some great-great-great-great grandparent that has a stable ID, or find a clever use of pseudo-selectors.
I work with RPA products that uses css selectors to find the elements to extract and interact with. A parent selector would be a big help on websites that have dynamic IDs and elements can only be located by their text (headings and table columns).
But I think the tools could provide the parent selection rather than the selector itself.
edit to previous no need for a class selector if you already know what the parent element is.
div:has(> .child) would give you the parent div.
When you think about it, it’s not really a parent selector we want but a parent combinator. A pseudo-class selector like the hypothetical
:parent
would behave like a filter on a list of tags matching the part of the selector before it, soli:parent
would take all of the<li>
tags and filter them, and returning you the matching<li>
, but in this case that’s not what we want at all—we probably want to select the<ul>
containing it.I’ve asked the CSSWG what syntax CSS authors can use to represent custom selector combinators (if you are going to DIY support for this yourself) and was told to use a pair of slashes, surrounding a custom IDENT that starts with a double dash, like
/--custom-combinator/
. Anybody desiring to support their own custom parent combinator in valid CSS syntax should support something like/--parent/
or whatever name makes sense to you, so that you could write a selector likeli /--parent/ ul {}
and it would target the<ul>
parent of every matching<li>
tag.Just for fun – we already support a custom parent combinator using this
/--parent/
syntax in our CSS at work, check it out here and play around with it yourself using process-css-demo: https://twitter.com/innovati/status/1207710819242463234I came across one today and thought of this article.
A modal with an .is-visible class that can select the body element and set overflow to ‘hidden’ to prevent scrolling in the background.