Closed dpk closed 1 year ago
almost like that?
/*/ use cases in post /*/
A P
/*/ description in post /*/
:is(A /*/ for A:root case /*/, :has(A)) P:not(:has(A))
Yeah I don't get the difference between p:within(a)
and a p
. See https://drafts.csswg.org/selectors-4/#descendant-combinators
If you just want to impose extra conditions, like foo p:within(a)
, then use foo p:is(a *)
Yup, a p
is what you want, and you can use :is()
as @Loirooriol said if you need to impose multiple ancestor conditions that aren't related to each other.
Note tho that your first example:
<div>
<a href="http://example.org/">
<p>I match
</a>
</div>
won't match the selector because, due to the way HTML parsing is defined, inline elements are auto-closed by a p
and then reopened inside of them. That is, the DOM structure produced by that markup is:
DIV
├ A href="http://example.org/"
└ P
└ A href="http://example.org/"
└#text: I match
(Your second example works as intended, because div
does not have that special behavior. So it is able to nest inside the a
without a problem, and then the p
sees that it has a div
parent and acts normally as well. HTML parsing has a lot of funky quirks that it's developed over the decades that HTML has been in use.)
This might be the source of your confusion!
Actually, the HTML parser can place both p
and div
inside an a
, but this doesn't happen if the end tag is missing like in the example. I think this is handled in https://html.spec.whatwg.org/multipage/parsing.html#adoption-agency-algorithm. So this works:
<!DOCTYPE html>
<style>a p { border: solid green }</style>
<div>
<a href="http://example.org/">
<p>I match</p>
</a>
</div>
Sorry, I think I didn’t explain the motivation for this. Obviously a p
will match this in the general case, but I mean this as a convenience/maintainability solution in quite highly nested cases like this:
.aleph {
/* ... styles for .aleph ... */
& .beth {
/* ... styles for .aleph .beth ... */
& .gimel {
/* ... styles for .aleph .beth .gimel ... */
& .daleth {
/* ... styles for .aleph .beth .gimel .daleth ... */
&:within(a) {
/* special styles for .daleth when within a link, regardless of where the a
is in the tree of .aleph .beth .gimel */
} } } } }
Afaict the only equivalent of this using the whitespace selector would be to write out the combinations by hand, and exiting the entire tree of selectors where the rest of the styles for .daleth
are:
a .aleph .beth .gimel .daleth,
.aleph a .beth .gimel .daleth,
.aleph .beth a .gimel .daleth,
.aleph .beth .gimel a .daleth {
/* special styles for .daleth within a link */
}
This is long-winded and gets even more complicated if one imagines situations such as .gewa:within(.bercna:within(.aza))
with a tree of selectors preceding it. The need to exit the tree of nested selectors is also bad for maintainability because it means all properties relevant to a particular style are no longer together in the stylesheet source.
I also don’t see how :is
can be used to solve this, but maybe I’m missing something.
Then you should use
.aleph {
/* ... styles for .aleph ... */
& .beth {
/* ... styles for .aleph .beth ... */
& .gimel {
/* ... styles for .aleph .beth .gimel ... */
& .daleth {
/* ... styles for .aleph .beth .gimel .daleth ... */
a & { /* or `&:is(a *)` works too */
/* special styles for .daleth when within a link, regardless of where the a
is in the tree of .aleph .beth .gimel */
} } } } }
Note that a &
only requires a
to be an ancestor of the element matched by the parent selector, basically it will behave like a :is(.aleph .beth .gimel .daleth)
.
Unlike a .aleph .beth .gimel .daleth
, a &
doesn't require a
to be an ancestor of .aleph
.
a &
doesn’t work because it violates the requirement that nested selectors have to start with a punctuation symbol, but &:is(a *)
does! Thanks!
AFAIK that requirement was dropped in 02db7b2e364bd3184e23ebb7f475e6b4347d5406
Good to know! But it’s still present in browsers (and, afaict, in the PostCSS plugin I’m using as a stopgap to support Firefox) so for now I still need to follow it
and, afaict, in the PostCSS plugin I’m using as a stopgap to support Firefox
As a side note, Firefox 117 will ship with nesting and without the punctuation symbol requirement.
Sebastian
Yup, that restriction got dropped a while back and implementations will follow. We can't fix legacy implementations by adding new features, as by definition they're not being updated. ^_^
Rough proposal: a pseudo-class, such as
p:within(a)
selectsp
elements which have ana
element anywhere in their ancestor tree.E.g. it would select any of the
<p>
elements here:But not this one:
While writing my first major design using CSS Nesting, this seemed like a missing feature, mainly for maintainability but also because truly accounting for all possible nesting situations to target the element wanted using regular selectors could be tricky within a complex nesting of selectors. A strong use case in particular (as implied above) is when elements might sometimes be inside links and sometimes not. This would allow them to be styled or restyled in a way more clearly indicating that they can be interacted with as links.
Link to spec: https://www.w3.org/TR/selectors-4/