Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[selectors][css-scoping] Should :host:has() match? #10693

Closed
tabatkins opened this issue Aug 5, 2024 · 15 comments
Closed

[selectors][css-scoping] Should :host:has() match? #10693

tabatkins opened this issue Aug 5, 2024 · 15 comments
Labels
Closed Accepted by CSSWG Resolution css-scoping-1 Current Work selectors-4 Current Work Tested Memory aid - issue has WPT tests

Comments

@tabatkins
Copy link
Member

In web-platform-tests/wpt#47441 a few tentative tests are suggested that test whether :host:has(...) works. The test author correctly notes that this isn't currently specified to work - only the logical combination pseudo-classes are allowed to match featureless elements and :has(), while defined in the "logical combination" section, isn't on the list of logical combo pseudo-classes.

I agree with the tester, tho, that this should work. :host h1 works just fine, so :host:has(h1) should work the same. I suggest that we add :has() to the list of pseudo-classes allowed to work on featureless elements.

(Note the first few tests in the WPT PR are testing the different scenario of :host(:has(...)), which is already well-defined to match, in a different way to what's discussed here. I'm talking about the latter three which are marked "tentative" in their filenames.)

@Westbrook
Copy link

Thanks for bringing the conversation here @tabatkins! I think the :host:has(…) combination will also be a boon to the in progress slot:has-slotted(…) API that is pending in #10586, and will be quite powerful as an appropriate customization of:host:has(slot:has-slotted). 🥹

@Loirooriol
Copy link
Contributor

To clarify, are you saying that both :host:has(h1) and :has(h1) should be able to match the host, or only the former?

In #10179 (comment) the idea is

Compound selectors are allowed to match the host only if all the contained simple selectors are allowed to match the host.

@tabatkins
Copy link
Member Author

tabatkins commented Aug 6, 2024

I think it should match in both cases, just like the logical combination pseudos. The reason the host is featureless is because you can't control the markup of the host element, and so it's easy to write a selector you expect to only match the markup you control (in the shadow) and have it accidentally match the host element due to the outer page doing things you can't predict.

This doesn't apply to :has() - it's matching based on markup you do control (in the shadow), and thus is completely predictable. Even if you use a complex selector in the :has() argument, because it's matching inside the shadow and uses that matching context, it can't match the host element unexpectedly. (That is, :has(.foo .bar) wouldn't be able to match just from the host element having a foo class; you'd need to write :has(:host(.foo) .bar) to make that happen, explicitly indicating that you're looking at the host element's markup.)

The only way to get an unexpected match is if you just forget the host element exists at all (because you generally don't pay attention to it), but that's a brain fart, not an unpredictable situation. I think that's okay. In particular, writing an unqualified :has() seems like a weird thing to do in the first place, which is the only way it would match the host without actually mentioning :host.

@kbabbitt
Copy link
Contributor

kbabbitt commented Aug 6, 2024

This would allow #10492 to be solved using :host:has(:popover-open), correct? We just had an internal developer run into that issue recently.

@tabatkins
Copy link
Member Author

Yes, that would work.

@tabatkins
Copy link
Member Author

(We should discuss this at the same time as #10179 fwiw; they're covering the same space.)

@emilio
Copy link
Collaborator

emilio commented Aug 8, 2024

Shouldn't this be about :host(:has(...))? I think :host:has() should generally not work to be consistent with other selectors like :host:nth-child(...) (which IIRC doesn't match)

@Westbrook
Copy link

:host(:has(…)) matches against light DOM children already, at least in Firefox and WebKit, and should continue to go so and expand to Baseline status as soon as possible. This aligns with :host(.class) et al also referencing things outside of the shadow root.

:host:has(…) should introspect the shadow root the same way :host > .child does. It would seem that:host:nth-child(…) should work in this way, as well.

@sorvell
Copy link

sorvell commented Aug 8, 2024

I think there are a few cases here that it would be great to untangle and specify.

Background

The spec defines Tree-Structural pseudo-classes, but it doesn't specifically distinguish the scope or relationship: ancestor or descendent.

Similarly, :host() matches the argument in the host's "normal context," the scope in which the host itself exists, not its Shadow DOM.

Additionally, there's a special carve out for the flat tree against which match :hover, :active, :target-within, and :focus-within. And the syntax uses the function version::host(:focus-within).

Currently, :host(:empty) works and matches against the host's light tree. As noted, :host(:has(...)) seems like it should work, but it's currently not well supported.

Discussion

When Shadow DOM is involved, for the cases defined in the spec, only a descendent relationship is relevant to consider since this could be either via the light or shadow tree or both, the composed tree.

The example noted above :host:nth-child(…) needs no consideration since it's based on an ancestor relationship (host within parent). It should never be able to match.

I believe only :has(...) and :empty are potentially ambiguous since they could match against the light, shadow, or flat tree.

Using the functional :host(...) syntax, it does seem like the spec is suggesting these should match against the light tree, and they do (minus bugs).

Matching these against the shadow tree does seem useful as is suggested here, and using the non-functional syntax also seems to make sense :host:has(...) or :host:empty (seems like this should also work).

Caveats

Adding the capability makes sense, but I see 2 downsides to using this syntax for it:
1. It's unclear if there's a mental model for when to use the functional syntax :host() and doing so changes the meaning. For example, why is it :host:after and not :host(:after)? At least only one of those works.
2. Using light v. shadow tree as a key for when to use the functional v. non syntax would break down for flat tree matching selectors like :host(:focus-within).

@tabatkins
Copy link
Member Author

Shouldn't this be about :host(:has(...))?

No. As I said in the initial comment, :host(:has(...)) is a separate thing that's already well-defined. This is about :host:has(...).

I think :host:has() should generally not work to be consistent with other selectors like :host:nth-child(...) (which IIRC doesn't match)

It's not clear if you've read my later comment giving a more thorough explanation for why I think :host:has() is fine to match. If you have read that, could you elaborate on how you disagree?

(And correct, :host:nth-child() does not match. While it would not be problematic for it to do so, since it only has access to the information in the shadow tree and thus always sees the host element as a lone sibling, it wouldn't be useful for it to do so either, for the exact same reason.)

@tabatkins
Copy link
Member Author

@sorvell You seem to be confusing yourself about what it means for :host(...) to take a selector argument, versus having selectors following :host. (And possibly have let emilio confuse you into thinking this issue is about :host(:has(...)), which it is not.)

  • :host(sel) matches the selector argument against the host element in the context of the outer (light) tree. If sel would match the host element in that context, then :host(sel) matches the host element within the shadow.
  • sel:host attempts to match the sel selector against the host element in the context of the inner (shadow) tree. Within the shadow, the host element is featureless, and only matches the exact selectors that are explicitly specified as allowed to match.

:host(::after) does not work because the host element does not match the selector ::after - it's not an ::after pseudo-element! This happens to be true in either context, but is certainly true in the light context. :host::after works because :host is allowed to match the host element, and then ::after isn't trying to match the host element, it's just a pseudo-combinator shifting you into matching the host's pseudo-elements; it's identical to :host > div in action.

@emilio
Copy link
Collaborator

emilio commented Aug 8, 2024

Yeah, sorry, it wasn't clear to me that the intention was to have :host:has() match the contents of the shadow tree.

I think it's a bit confusing that :host:has() and :host(:has()) would do such different things, fwiw, but it's not like I have a counter-proposal if this is something people need... It just feels a bit weird conceptually that we'd match the fragment's subtree but then forward the selector to the real element...

@sorvell
Copy link

sorvell commented Aug 8, 2024

:host(::after) does not work because the host element does not match the selector ::after

Thanks for the clarification, that makes sense.

Overall, this would be a valuable feature to add.

@tabatkins Do you think it makes sense to support :host:empty as well?

@tabatkins
Copy link
Member Author

@emilio

I'm not sure I understand the confusion. You have two entirely separate subtrees, both rooted in the same element; the two syntaxes match against one or the other. It seems unremarkable to me that they would do different things, because that's what happens for every other possible selector as well: normal selectors match against the shadow tree (which is where the stylesheet in question lives, so that's exactly what you'd expect), and :host(...) arguments match against the light tree.

@sorvell

Do you think it makes sense to support :host:empty as well?

Hm, yeah, that's workable under the same argument (it's only matching based on the non-host contents of the shadow, which are under the stylesheet author's control). It's only different from :host:has(*) in the case that the shadow contains text nodes but no elements, tho.

Not sure it's particularly useful - it seems a lot more likely that that component knows whether it's put anything inside the shadow tree, and in particular, a <style> in the shadow would prevent it from matching, but there are ways to attach stylesheets without inserting nodes, so I guess it's reasonable...

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [selectors][css-scoping] Should `:host:has()` match?, and agreed to the following:

  • RESOLVED: :host:has() can match, :has() can't
The full IRC log of that discussion <TabAtkins> :host:has(.foo)
<keithamus> TabAtkins: someone added tests in WPT combining :host:has. Some test well specified behaviour, but they added some tentative about using :host:has next to eachother in a compound selector
<keithamus> ... tentatively wrote assuming this works and it matches the host element assuming a .foo is in the tree
<keithamus> ... that doesn't work because :has doesn't match featureless elements in general
<keithamus> ... the :has pseudo class should be able to match the host. Again, :host is featureless because authors of the shadow tree cannot predict the markup so it would have to be written defensively
<emilio> q+
<keithamus> ... the :has pseudo class only matches based on descendents, ie stuff in the shadow tree thus already in control of the author
<keithamus> ... so predictable behavior and no defensive coding
<keithamus> ... there's also some examples this satisfies in the thread
<TabAtkins> :host:has(.foo) and :has(.foo) both are allowed to match
<keithamus> ... so :has should be added to the list of things to match the host element
<keithamus> ... also unqualified :has(.foo) should be able to match the host element
<keithamus> ... This is potentially confusing because no selectors currently match :host... nothing else can do this right now so it might not be expected.
<keithamus> ... The benefit of allowing is that matching behavior becomes much more sensible if it is allowed to match unreservedly
<emilio> Feels wrong that `*:has(..)` and `:has(..)` behaves differently
<keithamus> ... it makes speccing more complex if not
<keithamus> ... the simpler model, I think, is a little better
<astearns> ack emilio
<TabAtkins> *:is(:host) and :is(:host) already match different
<keithamus> emilio: I get the use case of matching inside the shadow tree, I'm not sure I agree with making it match when not qualified. It feels wrong that * doesnt match but unqualified does.
<keithamus> ... I guess you're right that's already the case per spec
<keithamus> ... something matching host that doesnt contain :host feels bad
<keithamus> ... I find it confusing. Especially as styles go outside your component
<keithamus> ... either force :host or do a new pseudo or something
<astearns> q+
<keithamus> ... I think I have a preference for enforcing :host especially as it doesn't change the behaviour for unqualified selectors
<keithamus> TabAtkins: I suspect that unqualified :has is rare to non-existent as it could potentially match all elements. I would be surprised if it causes problems
<keithamus> ... open to possibility that it would though
<astearns> ack astearns
<keithamus> astearns: I didn't go into the use cases but are the use cases presented for unqualified has that cannot be done with qualified has? Or is it ergonomics
<keithamus> TabAtkins: purely ergonomics, purely a matter of ergonomics/spec complexity to make it work one way or another
<keithamus> emilio: implementation complexity implies there is a benefit, then you can avoid looking at those selectors altogether
<keithamus> TabAtkins: but you would still know which selectors are potentially able to match
<keithamus> ... this expands the set of potential matches from things to the :host to things with unqualified :has
<keithamus> emilio: :is also complicates, but if you have :host in the subject it can only match the host. :has can match random stuff in the tree
<keithamus> emilio: I think unqualified :has matching :host is not great as an author
<keithamus> ... other than my gut feeling I dont have strong arguments one way or another
<keithamus> TabAtkins: are you implying theres a benefit to saying these selectors only apply to host or not? Being able to match either host or shadow tree is more complex?
<keithamus> emilio: yeah. We can put the selector in a separate place to style the element, otherwise it's in the general place
<keithamus> TabAtkins: the spec side, it means adding another clause to the conditions for what allows a compound selector to match a host element
<keithamus> ... not a huge complexity but one more thing in the list
<keithamus> emilio: spec or implementation complexity aside, I wonder what other authors think? A bare :has with random stuff inside accidentally matching the :host?
<keithamus> astearns: the person who wrote the tests is not thinking about this accidentally perhaps
<keithamus> ... I'd like to see what the valid use case is. Speaking personally, I think I'd like the use cases to justify this
<keithamus> TabAtkins: for the feature entirely? Or needing :host to be spelled out?
<keithamus> astearns: allowing a selector that doesn't explicitly use :host to match the host
<keithamus> emilio: you claim the test author mentioned that? As far as I can tell they don't test that
<keithamus> TabAtkins: all tests have :host:has. In the mindset of testing that :host matches appropriately.
<keithamus> TabAtkins: I'm fine with resolving with emilio's ammendment
<TabAtkins> :host:has() can match, :has() can't
<keithamus> PROPOSED RESOLUTION: :host:has() can match, :has() can't
<oriol> q+
<keithamus> oriol: I think this breaks the assumption from the previous issue
<keithamus> ... when we have compound selector allowed to match host, here has wouldnt be allowed but the combination would
<keithamus> ... so it breaks the general rule?
<keithamus> TabAtkins: changing that rule to special case this would be part of that resolution
<keithamus> oriol: so what would the general rule be?
<keithamus> TabAtkins: I'll show the spec
<keithamus> RESOLVED: :host:has() can match, :has() can't

@tabatkins tabatkins added the Tested Memory aid - issue has WPT tests label Aug 22, 2024
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Sep 30, 2024
Support `:host:has()` case to check whether a shadow host element has a
relationship between its shadow root node and shadow tree element:
- w3c/csswg-drafts#10693

Normally, `:has()` checks relationship between its anchor element and
the other elements in the same tree.

But in `:host:has()` case, `:has()` checks relationship in the shadow
tree of the anchor element. For example, `:host(.a):has(> div)`
matches a shadow host element if the host has `a` class value and the
shadow root of the host has a child div element.

To cross tree boundary for testing selector and invalidating styles,
this CL adds 'HasArgumentMatchInShadowTree' flag to the CSSSelector and
sets the flag while parsing selectors.

SelectorChecker and CheckPseudoHasArgumentTraversalIterator cross tree
boundary for `:has()` argument test traversal if the flag is set.

RuleInvalidationDataVisitor sets 'TreeBoundaryCrossing` invalidation-set
flag for non-subject `:has()` if the flag is set.

If StyleEngine reaches to a shadow host element while performing `:has()`
invalidation, it invalidates the host element if the host is affected by
`:has()` state change.

Bug: 359758910
Change-Id: I69f0813deca4caefcff1f0b5ff8181ba67967a40
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Oct 2, 2024
Support `:host:has()` case to check whether a shadow host element has a
relationship between its shadow root node and shadow tree element:
- w3c/csswg-drafts#10693

Normally, `:has()` checks relationship between its anchor element and
the other elements in the same tree.

But in `:host:has()` case, `:has()` checks relationship in the shadow
tree of the anchor element. For example, `:host(.a):has(> div)`
matches a shadow host element if the host has `a` class value and the
shadow root of the host has a child div element.

To cross tree boundary for testing selector and invalidating styles,
this CL adds 'HasArgumentMatchInShadowTree' flag to the CSSSelector and
sets the flag while parsing selectors.

SelectorChecker and CheckPseudoHasArgumentTraversalIterator cross tree
boundary for `:has()` argument test traversal if the flag is set.

RuleInvalidationDataVisitor sets 'TreeBoundaryCrossing` invalidation-set
flag for non-subject `:has()` if the flag is set.

If StyleEngine reaches to a shadow host element while performing `:has()`
invalidation, it invalidates the host element if the host is affected by
`:has()` state change.

Bug: 359758910
Change-Id: I69f0813deca4caefcff1f0b5ff8181ba67967a40
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5839398
Commit-Queue: Byungwoo Lee <blee@igalia.com>
Reviewed-by: Rune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1362877}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Oct 2, 2024
Support `:host:has()` case to check whether a shadow host element has a
relationship between its shadow root node and shadow tree element:
- w3c/csswg-drafts#10693

Normally, `:has()` checks relationship between its anchor element and
the other elements in the same tree.

But in `:host:has()` case, `:has()` checks relationship in the shadow
tree of the anchor element. For example, `:host(.a):has(> div)`
matches a shadow host element if the host has `a` class value and the
shadow root of the host has a child div element.

To cross tree boundary for testing selector and invalidating styles,
this CL adds 'HasArgumentMatchInShadowTree' flag to the CSSSelector and
sets the flag while parsing selectors.

SelectorChecker and CheckPseudoHasArgumentTraversalIterator cross tree
boundary for `:has()` argument test traversal if the flag is set.

RuleInvalidationDataVisitor sets 'TreeBoundaryCrossing` invalidation-set
flag for non-subject `:has()` if the flag is set.

If StyleEngine reaches to a shadow host element while performing `:has()`
invalidation, it invalidates the host element if the host is affected by
`:has()` state change.

Bug: 359758910
Change-Id: I69f0813deca4caefcff1f0b5ff8181ba67967a40
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5839398
Commit-Queue: Byungwoo Lee <blee@igalia.com>
Reviewed-by: Rune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1362877}
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Oct 8, 2024
Automatic update from web-platform-tests
Support `:host:has()`

Support `:host:has()` case to check whether a shadow host element has a
relationship between its shadow root node and shadow tree element:
- w3c/csswg-drafts#10693

Normally, `:has()` checks relationship between its anchor element and
the other elements in the same tree.

But in `:host:has()` case, `:has()` checks relationship in the shadow
tree of the anchor element. For example, `:host(.a):has(> div)`
matches a shadow host element if the host has `a` class value and the
shadow root of the host has a child div element.

To cross tree boundary for testing selector and invalidating styles,
this CL adds 'HasArgumentMatchInShadowTree' flag to the CSSSelector and
sets the flag while parsing selectors.

SelectorChecker and CheckPseudoHasArgumentTraversalIterator cross tree
boundary for `:has()` argument test traversal if the flag is set.

RuleInvalidationDataVisitor sets 'TreeBoundaryCrossing` invalidation-set
flag for non-subject `:has()` if the flag is set.

If StyleEngine reaches to a shadow host element while performing `:has()`
invalidation, it invalidates the host element if the host is affected by
`:has()` state change.

Bug: 359758910
Change-Id: I69f0813deca4caefcff1f0b5ff8181ba67967a40
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5839398
Commit-Queue: Byungwoo Lee <blee@igalia.com>
Reviewed-by: Rune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1362877}

--

wpt-commits: b40c843d18efb71ab2f1343ce53e82d06cdf7702
wpt-pr: 48383
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this issue Oct 9, 2024
Automatic update from web-platform-tests
Support `:host:has()`

Support `:host:has()` case to check whether a shadow host element has a
relationship between its shadow root node and shadow tree element:
- w3c/csswg-drafts#10693

Normally, `:has()` checks relationship between its anchor element and
the other elements in the same tree.

But in `:host:has()` case, `:has()` checks relationship in the shadow
tree of the anchor element. For example, `:host(.a):has(> div)`
matches a shadow host element if the host has `a` class value and the
shadow root of the host has a child div element.

To cross tree boundary for testing selector and invalidating styles,
this CL adds 'HasArgumentMatchInShadowTree' flag to the CSSSelector and
sets the flag while parsing selectors.

SelectorChecker and CheckPseudoHasArgumentTraversalIterator cross tree
boundary for `:has()` argument test traversal if the flag is set.

RuleInvalidationDataVisitor sets 'TreeBoundaryCrossing` invalidation-set
flag for non-subject `:has()` if the flag is set.

If StyleEngine reaches to a shadow host element while performing `:has()`
invalidation, it invalidates the host element if the host is affected by
`:has()` state change.

Bug: 359758910
Change-Id: I69f0813deca4caefcff1f0b5ff8181ba67967a40
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5839398
Commit-Queue: Byungwoo Lee <bleeigalia.com>
Reviewed-by: Rune Lillesveen <futharkchromium.org>
Cr-Commit-Position: refs/heads/main{#1362877}

--

wpt-commits: b40c843d18efb71ab2f1343ce53e82d06cdf7702
wpt-pr: 48383

UltraBlame original commit: 7bd6a635665974228495e9f678104df70bdae688
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this issue Oct 9, 2024
Automatic update from web-platform-tests
Support `:host:has()`

Support `:host:has()` case to check whether a shadow host element has a
relationship between its shadow root node and shadow tree element:
- w3c/csswg-drafts#10693

Normally, `:has()` checks relationship between its anchor element and
the other elements in the same tree.

But in `:host:has()` case, `:has()` checks relationship in the shadow
tree of the anchor element. For example, `:host(.a):has(> div)`
matches a shadow host element if the host has `a` class value and the
shadow root of the host has a child div element.

To cross tree boundary for testing selector and invalidating styles,
this CL adds 'HasArgumentMatchInShadowTree' flag to the CSSSelector and
sets the flag while parsing selectors.

SelectorChecker and CheckPseudoHasArgumentTraversalIterator cross tree
boundary for `:has()` argument test traversal if the flag is set.

RuleInvalidationDataVisitor sets 'TreeBoundaryCrossing` invalidation-set
flag for non-subject `:has()` if the flag is set.

If StyleEngine reaches to a shadow host element while performing `:has()`
invalidation, it invalidates the host element if the host is affected by
`:has()` state change.

Bug: 359758910
Change-Id: I69f0813deca4caefcff1f0b5ff8181ba67967a40
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5839398
Commit-Queue: Byungwoo Lee <bleeigalia.com>
Reviewed-by: Rune Lillesveen <futharkchromium.org>
Cr-Commit-Position: refs/heads/main{#1362877}

--

wpt-commits: b40c843d18efb71ab2f1343ce53e82d06cdf7702
wpt-pr: 48383

UltraBlame original commit: 7bd6a635665974228495e9f678104df70bdae688
i3roly pushed a commit to i3roly/firefox-dynasty that referenced this issue Oct 9, 2024
Automatic update from web-platform-tests
Support `:host:has()`

Support `:host:has()` case to check whether a shadow host element has a
relationship between its shadow root node and shadow tree element:
- w3c/csswg-drafts#10693

Normally, `:has()` checks relationship between its anchor element and
the other elements in the same tree.

But in `:host:has()` case, `:has()` checks relationship in the shadow
tree of the anchor element. For example, `:host(.a):has(> div)`
matches a shadow host element if the host has `a` class value and the
shadow root of the host has a child div element.

To cross tree boundary for testing selector and invalidating styles,
this CL adds 'HasArgumentMatchInShadowTree' flag to the CSSSelector and
sets the flag while parsing selectors.

SelectorChecker and CheckPseudoHasArgumentTraversalIterator cross tree
boundary for `:has()` argument test traversal if the flag is set.

RuleInvalidationDataVisitor sets 'TreeBoundaryCrossing` invalidation-set
flag for non-subject `:has()` if the flag is set.

If StyleEngine reaches to a shadow host element while performing `:has()`
invalidation, it invalidates the host element if the host is affected by
`:has()` state change.

Bug: 359758910
Change-Id: I69f0813deca4caefcff1f0b5ff8181ba67967a40
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5839398
Commit-Queue: Byungwoo Lee <blee@igalia.com>
Reviewed-by: Rune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1362877}

--

wpt-commits: b40c843d18efb71ab2f1343ce53e82d06cdf7702
wpt-pr: 48383
ErichDonGubler pushed a commit to erichdongubler-mozilla/firefox that referenced this issue Oct 11, 2024
Automatic update from web-platform-tests
Support `:host:has()`

Support `:host:has()` case to check whether a shadow host element has a
relationship between its shadow root node and shadow tree element:
- w3c/csswg-drafts#10693

Normally, `:has()` checks relationship between its anchor element and
the other elements in the same tree.

But in `:host:has()` case, `:has()` checks relationship in the shadow
tree of the anchor element. For example, `:host(.a):has(> div)`
matches a shadow host element if the host has `a` class value and the
shadow root of the host has a child div element.

To cross tree boundary for testing selector and invalidating styles,
this CL adds 'HasArgumentMatchInShadowTree' flag to the CSSSelector and
sets the flag while parsing selectors.

SelectorChecker and CheckPseudoHasArgumentTraversalIterator cross tree
boundary for `:has()` argument test traversal if the flag is set.

RuleInvalidationDataVisitor sets 'TreeBoundaryCrossing` invalidation-set
flag for non-subject `:has()` if the flag is set.

If StyleEngine reaches to a shadow host element while performing `:has()`
invalidation, it invalidates the host element if the host is affected by
`:has()` state change.

Bug: 359758910
Change-Id: I69f0813deca4caefcff1f0b5ff8181ba67967a40
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5839398
Commit-Queue: Byungwoo Lee <blee@igalia.com>
Reviewed-by: Rune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1362877}

--

wpt-commits: b40c843d18efb71ab2f1343ce53e82d06cdf7702
wpt-pr: 48383
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this issue Oct 15, 2024
Automatic update from web-platform-tests
Support `:host:has()`

Support `:host:has()` case to check whether a shadow host element has a
relationship between its shadow root node and shadow tree element:
- w3c/csswg-drafts#10693

Normally, `:has()` checks relationship between its anchor element and
the other elements in the same tree.

But in `:host:has()` case, `:has()` checks relationship in the shadow
tree of the anchor element. For example, `:host(.a):has(> div)`
matches a shadow host element if the host has `a` class value and the
shadow root of the host has a child div element.

To cross tree boundary for testing selector and invalidating styles,
this CL adds 'HasArgumentMatchInShadowTree' flag to the CSSSelector and
sets the flag while parsing selectors.

SelectorChecker and CheckPseudoHasArgumentTraversalIterator cross tree
boundary for `:has()` argument test traversal if the flag is set.

RuleInvalidationDataVisitor sets 'TreeBoundaryCrossing` invalidation-set
flag for non-subject `:has()` if the flag is set.

If StyleEngine reaches to a shadow host element while performing `:has()`
invalidation, it invalidates the host element if the host is affected by
`:has()` state change.

Bug: 359758910
Change-Id: I69f0813deca4caefcff1f0b5ff8181ba67967a40
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5839398
Commit-Queue: Byungwoo Lee <bleeigalia.com>
Reviewed-by: Rune Lillesveen <futharkchromium.org>
Cr-Commit-Position: refs/heads/main{#1362877}

--

wpt-commits: b40c843d18efb71ab2f1343ce53e82d06cdf7702
wpt-pr: 48383

UltraBlame original commit: 7bd6a635665974228495e9f678104df70bdae688
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Closed Accepted by CSSWG Resolution css-scoping-1 Current Work selectors-4 Current Work Tested Memory aid - issue has WPT tests
Projects
None yet
Development

No branches or pull requests

7 participants