The closest combinator (<)
Sometimes you see the question "is there a parent combinator in CSS"? And the answer is always "no."
There is now CSS :has(), which can do a similar thing for static CSS, but isn't quite the same thing.
In ACSS, you often want to target a specific parent when you click on a child element.
In ACSS, there is a special combinator that can be used to find target selectors higher up the DOM tree, the "<" sign.
In ACSS this combinator is only used for finding target selectors - not event selectors - for performance reasons.
This is a helpful combinator in ACSS, and definitely worth remembering. It is very handy for applying actions to parent elements.
How does it work in ACSS? Let's see an example.
Let's say you want to click on an <li> tag. When you click on the <li> tag, you want to put a class on the container <ul> tag saying that an <li> tag has been selected.
That's quite a common scenario.
You could do this:
li:click {
& < ul {
add-class: .selected;
}
}
That would find the closest <ul> tag to the <li> tag that was clicked on.
But what if you wanted to affect not just the closest <ul> tag, but something next to it, like the next sibling element? What if you want to render something on the <p> tag immediately following the <ul> tag? What could you do? You could do this:
li:click {
& < ul + p {
render: "You just clicked on an li tag.";
}
}
Note what happened there. We found the closest <ul> tag and then used a regular CSS combinator, the "+" sign, to get the <p> tag that immediately followed it in the DOM tree.
If you had an attribute in the li tag that contained some text to render and wanted it to appear in that <p> tag when it was clicked, you could do this:
li:click {
& < ul + p {
render: "{@data-some-text-in-an-li-tag}";
}
}
All the regular CSS combinators are supported - not just the "+" sign.
That's great, but what happens if you put a selector after that combination, how does it behave then?
Well, you can use it to go back down the DOM, or enter a shadow DOM or an iframe, go up and down the DOM for a while just for a laugh, or whatever you like.
Everything after the selector that is immediately after the closest combinator acts like a regular CSS selector.
Let's say there is a shadow DOM that you want to intrude into to do something when you click on the <li> tag, and it is halfway across the rest of the page.
You could do this:
li:click {
& < main .section .shadowHost -> p {
render: "That's weird. I'm in a shadow DOM and you just clicked on a random li tag, and now in here it says {@data-what-im-saying-is}";
}
}
That would go up from the <li> tag to the <main> tag, down to its inner ".section" class element, down to its ".shadowHost" class element which happens to host a shadow DOM, and then the "->" combinator takes you into the shadow DOM and you then hijack all the p tags and display a comment in them.
So this is quite a powerful feature. It is not only a "parent", "ancestor" or "closest" combinator, but in combination with other CSS selectors it allows up and down the DOM navigation to specific targets.
It is probably most useful when you run an event (like a click or a mouseover) on an element and want to do something to its container element, such as add a class to it. It saves on having to do fancy workarounds.