`has()` for form validation really looked interesting but then I saw on their first example in your link that it is not supported in Firefox https://caniuse.com/css-has
I dream that one of these days, CSS will get a selector similar to `has()`, but that can target text content, not the structure. E.g. I want to be able to write something like:
article a :has_("click here ")
to select elements that are otherwise hard or impossible to target. Of course, I don't want to use it on the websites - I want it for userstyles, so I can swiftly and efficiently deal with the insanely bad UX of most of webpages, despite their authors making it hard to fix (often on purpose).
That, and I'd like some way to punch through shadow DOM, because as far as I can tell, elements in the shadow DOM cannot be addressed by userstyles at all, which prevents me from fixing annoyances in some webapps (looking at you, Gerrit).
The only problem with that is that uBO applies it via JS polling (I think?) and this results in the unstyled content flashing very briefly. Pretty annoying sometimes; hope it also gets into a standard (or jyst gets a native implementation for the sake of adblocking).
My idea of a better web browser design is some CSS commands which are only available for user styles, including these features (text content, shadow DOM, etc; although, such things might also be useful even if not restricted to user styles) and some others, such as more control over priority, and overriding the meaning of other CSS commands (which are restricted to only being allowed in user styles).
In some contexts, which includes JavaScript and thus user styles, you can use XPath, which interacts with all nodes, not just element nodes like CSS. Your sample selector would be this, if I have understood your intention correctly¹ (that you’re targeting the <a> element, and don’t care if the text “click here ” is an immediate child, or spread across multiple children):
//article//a[contains(., "click here ")]
The equivalent to document.querySelector in JavaScript:
document.evaluate(
'//article//a[contains(., "click here ")]',
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null,
).singleNodeValue
And the document.querySelectorAll (which returns a static node list) equivalent would use ORDERED_NODE_SNAPSHOT_TYPE, with .snapshotLength and .snapshotItem(index) on the result object. Yes, this API is written in a very old style, and could do with being wrapped in a more pleasant API.
As for shadow DOM: yeah, you can’t target closed shadow DOMs at all in any way, by design. Fortunately most are open so that it is at least possible to get into them, even if it’s a pain since the normal tools can’t pierce the boundary.
—⁂—
¹ If you wanted to only match “click here ” in an immediate child text node of the <a> element, these four work and are equivalent:
//article//a[./text()[contains(., "click here ")]]
//article//a[text()[contains(., "click here ")]]
//article//a[contains(./text(), "click here ")]
//article//a[contains(text(), "click here ")]
These will be more efficient than the first-used selector. Where CSS is mostly unaffected by selector complexity because it largely evaluates from right to left, XPath is more likely to be doing full traversals, which will benefit from more specific selectors, hence things like prefixing paths with /html/body, or only evaluating in document.body, in order to skip traversing the head altogether, if that will never match; and you can easily imagine that contains(//a/text(), "…"), which selects text nodes that are children of <a> elements and thus has selected nodes that have a trivial string-value, will be faster than contains(//a, "…"), which will need to stringify every <a> element, entailing further traversal and string construction. Mind you, the differences in all this will mostly be very small in practical terms.
That, and I'd like some way to punch through shadow DOM, because as far as I can tell, elements in the shadow DOM cannot be addressed by userstyles at all, which prevents me from fixing annoyances in some webapps (looking at you, Gerrit).