w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.52k stars 673 forks source link

[css-cascade] may need to define cascading order between sibling encapsulation contexts #10889

Open dbaron opened 2 months ago

dbaron commented 2 months ago

The cascading spec defines cascading by encapsulation context as:

When comparing two declarations that are sourced from different encapsulation contexts, then for normal rules the declaration from the outer context wins, and for important rules the declaration from the inner context wins. For this purpose, [DOM] tree contexts are considered to be nested in shadow-including tree order.

This doesn't say what happens when comparing declarations from encapsulation contexts that are not directly inside or outside of each other.

I don't think this is relevant in CSS today. However if either of the following happens:

then I think we need to define the cascading order between sibling encapsulation context. For example, if you have an element A (with a shadow DOM that exposes a part P) that is itself slotted into the shadow DOM of a different element B, then this would be needed to define how a regular style styling the P element inside the A shadow DOM cascades with a ::slotted()::part() style inside of the B shadow DOM that styles the same element.

Maybe the reference to shadow-including-tree-order is intended to define this, but if it is it probably needs language more specific than "inside" and "outside".

(It might be both extra implementation complexity and possibly also a source of author confusion if the rules from sibling encapsulation contexts mix with each other as thought they're at the same "context" level.)

tabatkins commented 2 months ago

Ooh, didn't realize that was potentially possible. Yeah, I think just using shadow-including tree order is the way; that's a superset of the existing in/out relationship.

css-meeting-bot commented 2 months ago

The CSS Working Group just discussed [css-cascade] may need to define cascading order between sibling encapsulation contexts.

The full IRC log of that discussion <emilio> dbaron: one of the steps in the cascade, between origin and specificity
<emilio> ... (don't remember how it interacts with layers)
<emilio> ... is that rules based on tree scopes cascade separately
<emilio> ... so rules from outside the shadow root generally wins, except !important which goes the other way around
<emilio> ... there's spec text that assumes that only tree scopes relevant to styling are outside / inside
<emilio> ... but in some edge cases you can have sibling scopes
<emilio> ... one of these is if we allow ::part() after ::slotted()
<emilio> ... the other is the /slotted/ combinator
<emilio> ... so in these cases you have stuff in one shadow tree that affects styles in a sibling shadow tree
<emilio> ... the cascade spec is not clear about this
<emilio> ... I don't really have a solution, thinking about this makes my head hurt
<emilio> ... for an impl perspective is probably easier not to cascade them together
<emilio> ... because having them together may be painful
<emilio> ... the problem here is we don't define what happens
<emilio> ... I don't have very strong opinions
<emilio> q+
<dandclark> q+
<emilio> Rossen: tab seems to propose tree order
<astearns> ack lea
<Zakim> lea, you wanted to say, it's definitely not high priority. Q: if we decide to not allow it now, is that something we can revisit later or will we run into web compat?
<lea> q+
<Rossen9> ack emilio
<dandclark> emilio: The shadow incluuding tree order thing makes sense except I don't know how to define !important in that case beacuse there's no inside or outside. Not clear if it should be reversed or not, that seems weird. So don't have clear answer.
<emilio> dandclark: Was going to agree with tab
<emilio> ... it generalizes that definition
<emilio> ... but agree with emilio that it seems weird to do the reverse from !important
<Rossen9> ack dandclark
<Rossen9> ack lea
<emilio> ... unclear if there's something better
<emilio> lea: not quite sure I understand so might be off
<emilio> ... not sure how making slotted a combinator relates to this
<emilio> ... the whole point was to circumvent some of the issues
<emilio> ... wouldn't it be the same as
<emilio> ... you're using regular selectors to target the slotted elements
<emilio> ... so regular cascade rules should apply
<emilio> ... if it's about styling inside and outside we have :host and regular selectors too
<emilio> ... maybe I'm misunderstanding
<emilio> q+
<emilio> dbaron: I think it'd be the /slotted/ combinator in combination with ::part or something else
<Rossen9> ack emilio
<emilio> dbaron: I think I was thinking was something like /slotted/ element::part(foo) from inside a component
<dandclark> emilio: No because the outside is not a sibliing
<emilio> ... then slotted looks at the parent tree scope, and ::part() could be a child of the parent tree scope (thus a sibling)
<emilio> lea: wouldn't that be the same as targetting the part from outside?
<emilio> emilio: no because outside scope wouldn't be a sibling
<emilio> dbaron: the other possibility is that some of the rules are not desirable with ::slotted()
<emilio> lea: that's a big motivation for the slotted combinator
<lea> that any CSS you include in ::slotted() has lower precedence than litterally any other CSS, including the universal selector, CSS resets, generic type selectors etc
<emilio> q+
<lea> unless you use !important, which is too strong
<Rossen9> ack emilio
<dandclark> emilio: I am confused because the slotting behavior doesn't fix that layout
<emilio> lea: my understanding was that ::slotted() behaves like this because it's a pseudo of the slot
<emilio> emilio: that's not correct
<emilio> lea: so this is the reason ::slotted() doesn't work?
<emilio> dbaron: yes, the reason ::slotted() is so weak is this rule about encapsulation context
<emilio> ... which I think makes sense for ::part()
<emilio> ... but maybe it's not the right decision for ::slotted()
<emilio> lea: but now we cannot change ::slotted() because of webcompat
<emilio> ... so /slotted/ would work
<emilio> ... btw I chatted with rniwa, and his implementation concerns are about targetting descendants and other elements
<emilio> ... but if we restrict what comes after to a compound selector he's fine with it
<emilio> q+
<Rossen9> ack emilio
<lea> q+
<dandclark> emilio: So that is correct, that was an implementation issue, but making @@@ doesn't help as long as we don't change the cascade spec in subtle ways.
<Rossen9> ack lea
<emilio> lea: it's clear we need to fix both
<keithamus> s/@@@/slotted combinator
<emilio> ... but we probably can't change how ::slotted() behaves because webcompat
<emilio> q+
<dandclark> emilio: I am not sure that's necessarily true. Does need some investigation . RIght now in the cascade spec all @@@ have hte same behavior. So it would feel weird to change the behavior only because multiple selectors can match
<dandclark> ...we could try to fix the cascade spec
<dandclark> ...but that's sort of tangential to this issue
<dandclark> ...but should do that if that's what we really want
<lea> https://github.com/w3c/csswg-drafts/issues/7922#issuecomment-2380098440
<emilio> lea: there are a lot of other things that need to be fixed, see ^
<keithamus> q+
<dandclark> emilio: Seems there's no clear consensus
<emilio> ack emilio
<Rossen9> ack keithamus
<emilio> keithamus: Can you style `:has()` with a combinator? So you'd do `:has(/slotted/ something)`
<emilio> lea: yeah `:has()` supports relative selectors
<emilio> ... first example in mdn
<emilio> Rossen9: let's take this back to the issue