Let's define the behavior of ::slotted (a tentative name).
I am aware that CSS Scoping should define it, but let's have a rough consensus here.
I remember that I had discussion, maybe in www-style?, that we should make ::content take only a simple selector, instead of a selector. Polymer guys told us that styling a _direct child_ of an insertion point is the only use case of ::content in Polymer.
e.g.
::content(div)
That should be interpreted as ::content > div in the previous syntax.
We no longer support a selector as its argument, like ::content(div p)
We might want to make ::slotted have this restriction because this makes the implementation simpler.
See also https://github.com/w3c/webcomponents/issues/308#issuecomment-143655347 because the definition of ::slotted will depend on those incoming changes.
I recently did a search through the Basic Web Components project looking for where we currently use ::content. We concur with Polymer: the only cases where we currently use ::content are trying to style the direct children of an insertion point.
Regarding the name of this selector, it seems that the term "slotted" here is being used as a synonym for "assigned". For consistency with the use of "assigned" in the spec, and with existing API members such as getAssignedNodes(), perhaps this selector could be called ::assigned. That would reduce the number of terms and concepts a developer needs to learn here.
@JanMiksovsky . Thank you! That's exactly the information I'd like to see.
Regarding the name of this selector, I'm afraid that ::assigned might be a confusing name.
In this example,
https://w3c.github.io/webcomponents/spec/shadow/#composition-example
T::assigned(*) should match H and P. O and P.Yeah, if we're making this pseudo element flatten slot elements' assigned node lists, then we should probably refrain from using the term "assigned". Also, someone pointed out that "assigned" might sound too generic while "slotted" sounds a lot more related to slot elements.
We don't need to wait for https://github.com/w3c/webcomponents/issues/308#issuecomment-143655347. The following (tentative) definition could be enough:
A::slotted(simple_selector) matches a node B if and only if:
Let me confirm:
For Shadow DOM V0, the following pattern is often used:
::content > div { color: blue; }
The color: blue is applied to <div>, not the parenting <content>.
(and in the selector matching, ::content matches <content>, of course)
In the proposed ::slotted() for V1, an author would expect the same as above by:
::slotted(div) { color: blue; }
If @hayatoito's comment above is adopted, the color: blue is applied to <div>
(which is node _B_ in the comment), not the parenting <slot> (which is node _A_).
Obviously if an author wants to style <slot> element itself,
it can write slot { color: blue; } and no fancy pseudo class/element should be required,
so the matching logic in the above comment should be correct, but let me confirm.
(I was a bit confused by the name, btw)
Let me clarify the definition:
A::slotted(simple_selector) matches a node B if and only if:
Does it make sense?
Thanks, it is clearer now.
Another question: Do we allow ::slotted without function-style parameter?
In that case, any element slotted under <slot> would match the rule?
In the default slot case, text node could match the rule, then?
E.g. ::slotted would be almost equivalent to ::slotted(*), but if a text node is slotted under a
<slot>, it might be different.
In shadow's style:
::slotted { color: green; }
::slotted(*) { color: blue; }
where in this HTML:
<div>
:shadow-root
<slot name="blue"></slot>
<slot></slot>
<div slot="blue">This text should be in blue.</div>
<div>(1)Is this color blue?</div>
(2)Is this color green?
</div>
In my opinion, ::slotted is allowed, but it must be equivalent to *::slotted(*) and it never matches
slotted text node.
In a general rule, you cannot select text nodes with CSS selector, even with *. :)
"::slotted" (without parameter) is disallowed. It is invalid as if "div >" is invalid as a selector.
A::slotted(simple_selector)matches a node B if and only if:
- Selector _A_ matches a slot, called _SLOT_
- B is a member of the _distributed nodes_ of SLOT
- and, _simple_selector_ matches B
Ops. I meant a "compound selector" here, instead of a "simple selector". The motivation is to disallow "combinator" being used.
Thus, the definition should be:
A::slotted(compound_selector) matches a node B if and only if:
e.g. slot[name="slot1"]::slotted(div.foo)
I expect that this does not increase the difficulty of the implementation, however, this gives us much flexibility. :)
How do you target pseudo elements of the slotted element?
::slotted(div.foo::before) or ::slotted(div.foo)::before ?
Good question. I've never thought this case. :)
::slotted(div.foo::before)
This did not work, _as intended_, IMO. We might not want to support this because a pseudo element, which "::before" _matches_, is not a member of a distributed nodes of SLOT. This should not match.
or ::slotted(div.foo)::before ?
How to support this kind of consecutive pseudo elements is up to each pseudo element. In this case, it's up to "::slotted" pseudo element.
In a general rule, selectors have a limitation about what can be followed after a pseudo element.
I'm +1 not to support this unless we have a strong use case.
I'd like "::slotted" be valid only when it is the _last item_ in a selector, as of now.
On Tue, Jan 12, 2016 at 2:53 AM, Hayato Ito [email protected]
wrote:
Good question. I've never thought this case. :)
::slotted(div.foo::before)
This should not behave _as intended_, IMO. We might not want to support
this because a pseudo element, which "::before" _matches_, is not a
member of a distributed nodes of SLOT. This should not match.or ::slotted(div.foo)::before ?
How to support this kind of consecutive pseudo elements is up to each
pseudo element. In this case, it's up to "::slotted" pseudo element.In a general rule, selectors have a limitation about what can be followed
by a pseudo element.
I'm +1 not to support this until we have a strong use case of this.Not a strong use case perhaps, but:
where the shadow tree for is:
Fwiw, this currently works with ::content in Blink using "::content
item::before".
Also, this is quite similar to :host and :host-context. They happen to be
pseudo classes, not pseudo elements, but they select real dom elements in a
different (shadow) tree than the selector's origin, just like ::slotted.
:host()/:host-context()::before currently works in Blink.
In a general rule, the support is poor
Note: Note that, unless otherwise specified in a future specification,
pseudo-classes other than the user action pseudo-classes are not valid when
compounded to a pseudo-element; so, for example, ::before:first-child is an
invalid selector.—
Reply to this email directly or view it on GitHub
https://github.com/w3c/webcomponents/issues/331#issuecomment-170756648.
Rune Lillesveen
Yeah, I do not have a strong opinion on this as long as the support cost do not get increased.
AFAIR, the selector spec said that a selector can not have multiple pseudo elements being used at the same time, but it looks this limitation was removed from the editor's draft.
Regarding with ::before and ::after, I think it's okay to support if we can support that easily.
@tabatkins,
Can we allow multiple pseudo elements _in a row_? e.g. ::slotted(div)::before
Is this a right direction?
I think there is no significant contentious bits about ::slotted pseudo elements.
@tabatkins, could you update the CSS Scoping? Is the current rough definition good enough to spec it in the CSS Scoping?
Well, weren't @rniwa and @hober saying that they would prefer styling <slot> directly? If you can do that, why would we have ::slotted?
"::slotted" is used to style a distributed node directly, having a more power.
e.g.
slot::slotted(div.red) {
color: red;
}
slot::slotted(div.green) {
color: green;
}
The following might be _roughly_ equivalent to style a <slot>.
slot::slotted(*) {
color: green;
}
Fair.
Does a distributed node get all rules from each slot that it went through applied?
Let's say an element X is assigned to a slot A, and the slot A is assigned to another slot B. So the X's _final_ slot is B. Now, let's say both A's shadow DOM and B's shadow DOM have ::slotted rules that match X.
Should the rule in A's shadow DOM be applied to X? Or would it be ignored and only the rule in B's shadow DOM is applied?
Does a distributed node get all rules from each slot that it went through applied?
Yes, that's an intended behavior. A distributed node gets all rules from each slot.
::content, the former _name_ of ::slotted, has a similar behavior. A distributed nodes gets all rules from all insertion points. This behavior has not changed in this sense.
I am no sure which is desired behavior, each slot or only final slot. I do not recall it being discussed.
Here's the example for @rniwa
http://jsbin.com/yequpu/edit?html,js,output
<div id="host">
:shadow-root
<style>::slotted(span) { color: green; background-color: yellow; }</style>
<div id="host2">
:shadow-root
<style>::slotted(span) { color: red; }</style>
<slot name="slot2"></slot>
<slot name="slot1" slot="slot2"></slot>
</div>
<span slot="slot1">Hello, Shadow DOM</span>
</div>
In current Blink's implementation, first { color: green; background-color: yellow; } is applied,
then { color: red; } is applied on top of it -> result is { color: red, background-color: yellow; }.
Just a note. We still use our broken cascade order from v0 in Blink, so we shouldn't trust the current order from Blink in general right?
Yeah, we just implemented that behavior in http://trac.webkit.org/changeset/197316.
@rune-opera, thanks for pointing it out.
Yeah, if the #316 is applied,
<span> is in the outermost scope<style green/yellow> is in the outer shadow.<style red> is in the inner shadow.That means, that green/yellow style wins against red rule, correct?
Yes.
@TakayoshiKochi , could you upstream this to css scoping, as you did in
https://github.com/w3c/webcomponents/issues/316#issuecomment-193162039 ?
I am happy to help, but I think you are the best person. :+1:
sure, will do.
Posted
https://lists.w3.org/Archives/Public/www-style/2016Mar/0170.html
and will follow-up.
@TakayoshiKochi
Could you follow-up? It looks there is no reaction in www-style, as I expected. :)
I'm contacting @tabatkins to get the spec updated.
All done, and reply sent to the list. https://lists.w3.org/Archives/Public/www-style/2016Apr/0239.html Please review!
Oh yeah, I haven't yet defined pseudo-element handling. Which do y'all prefer:
::slotted(.foo::before)::slotted(.foo)::beforeI don't have a strong opinion either way.
I think I'd prefer ::slotted(.foo)::before because it's similar to how you add ::before/::after on hosts.
Blink currently supports ::before/::after on hosts using
:host(.foo)::before
not
:host(.foo::before)
:host-context(.foo::before) would be strange also.
Right, that's because :host() always represents the host element; it just uses the argument to query the tree to see if it should match or not. Putting ::before inside the argument wouldn't make any sense - you dont' want to check if an ancestor has a ::before pseudo-element.
::slotted, on the other hand, uses its argument to decide _which_ of its assigned slotables it's supposed to represent. As such, it makes a _little_ more sense to have ::before inside.
(At least, it makes as much sense as using doing something like :matches(.foo, .foo::before), which is allowed.)
I don't have a problem with ::slotted(.foo)::before, it just means dealing with chained pseudo-elements. Which we had before, so it's probably not a problem.
I'll also note that if you're drawing parallels between :host() and ::slotted(), authors probably will too - they select up and down outside the shadow tree. Having them work as similarly as possible (main difference being the number of colons) is probably good for comprehension. So that's an argument for ::slotted()::before.
It seems weird though since it addresses a box inside .foo, not inside ::slotted.
Thank you, @tabatkins !
I reviewed quickly. Here are my comments:
The descendants of a shadow host (its light tree) must not generate boxes in the formatting tree. Instead, the contents of the shadow tree generate boxes as if they were the contents of the shadow host instead.
In several instances in shadow DOM, elements don’t have element parents (instead, they may have a shadow root as parent, or something else). An element without a parent, or whose parent is not an element, is called a top-level element.
While a shadow host’s light tree does not generate boxes normally, its light tree direct children can be explicitly pulled into a shadow tree and forced to render normally. This is done by marking the child as slotable and then, in the shadow tree, creating a slot set to receive the slotable, making the element assigned to the slot. (Anonymous text nodes that are direct children are always slotable.)
Since the actual logic, "Which elements generate a box?", should be explained by the concept of the flat tree ,
can we avoid to explain that in details here?
I'm wondering how to state it simply in css scoping. The current Shadow DOM spec has the followings in the section of Flat trees:
A document flat tree is a flat tree whose root node is a document
A node is in a document flat tree if it participates in a document flat tree.
Unless an element is in a document flat tree, the element must not create any CSS box.
In resolving CSS inheritance, an element must inherit from the parent node in the flat tree, if applicable.
User agents must use the document flat tree in the visual formatting model, instead of the document tree.
I think we should upstream these sentences to CSS scoping. I guess these sentences need to be refined somehow to match the css scoping world.
DOM Standard does not need a flat tree. I think only css scoping is a client of a flat tree. Thus, eventually, we need to upstream _a flat tree_ to CSS.
3.1. Shadow DOM Selection Model
Elements in the DOM have zero or more shadow trees.
This can be:
Elements in the DOM have zero or _one_ shadow tree.
Yeah, multiple shadow trees are removed.
Otherwise, we might want to omit this because it looks a duplication of the HTML Standard.
3.1.1. Shadow Hosts in a Shadow Tree
For the purpose of Selectors, a shadow host also appears in each of its shadow trees, with the contents of the shadow tree treated as its children. If an element has multiple shadow trees, it appears in each shadow tree’s context independently; each shadow tree sees itself as the contents of the shadow host, not the other shadow trees.
This can be:
For the purpose of Selectors, a shadow host also appears in its shadow tree, with the contents of the shadow tree treated as its children.
because multiple shadow trees are removed.
3.1.2. Slots and Slotted Elements in a Shadow Tree
If a slot is not assigned any of its shadow host’s children, that slot’s own children are assigned to it. Otherwise, a slot’s DOM children must not generate any boxes, as if they were display:none.
Slots can, themselves, be assigned to a slot in a deeper shadow tree. If this occurs, the elements assigned to the first slot are also treated as being assigned to the deeper slot. The deepest slot that an element is assigned to is its final assigned slot.
Elements assigned to a slot must generate boxes as if they were children of their final assigned slot (rather than children of their actual parent in a shadow host’s light tree).
I think we can remove these sentences. If we use the flat tree in the previous section, we do not need to mention a slot here as a special case.
3.2.2. Selecting Slot-Assigned Content: the ::slotted() pseudo-element
The ::slotted() pseudo-element represents the elements assigned to a slot. This pseudo-element only exists on slots.
"::slotted()" represents "distributed nodes", instead of "assigned nodes".
"assigned nodes" and "distributed nodes" are different.
I think you can refer this as the definition of "distributed".
In 3.2.2,
::slotted( <compound-selector>? )
If the
<compound-selector>is omitted, it defaults to the universal selector.
We haven't discussed this in this issue before, and when I implemented in Blink I made the <compound-selector> mandatory, not be omitted. As :host has 2 forms (:host and :host()) and the latter the parameter is not omissible, the difference may be confusing.
@tabatkins, can this <compound-selector> be mandatory parameter and author must specify * explicitly if it wants?
@annevk ::slotted does not represent anything on its own; it's an aliasing pseudo-element (the first of its kind, I guess) rather than a box-creating pseudo-element. In other words, it functions kinda like a combinator, but with limitations (one compound selector).
@TakayoshiKochi Yeah, I can make the argument mandatory.
@hayatoito Thanks for the review!
I hadn't caught that multiple shadow roots were removed; I'll fix.
For the rest of your comments, I will (a) rephrase the explanatory part to be clearer that I'm not trying to redefine anything from DOM, just provide some framing for everything else in the spec (so people don't have to go read and understand DOM just to understand what I'm talking about), and (b) pull in all the flattening/distributing stuff so you can remove it from Shadow DOM.
Between DOM and CSS Scoping, it looks like nearly all of Shadow DOM is getting eaten by other specs, so we should be able to remove most or all of it soon!
I've finished all the edits; they ended up necessitating a larger reorg/rewrite than I'd expected! Scoping now defines the flattened tree, too.
Closing this issue because the behavior is largely defined in the CSS scoping spec. We can file a new issue to track the remaining issues if there are any.
Stop closing this issue, people won't suddenly forget they need this.
Stop closing this issue, people won't suddenly forget they need this.
?? ::slotted is already supported by all major browser engines as far as I know. If you have specific issues to discuss, file a new issue in CSS scooping spec. There is nothing left to discuss in the broader web components community at the moment.
Yes, ::slotted is supported everywhere, but ::slotted still doesn't allow to styling child nodes, which make them completely useless for anyone who care about UI.. Perhaps there's a way i don't know? But i sure as hell search for it!! If not, what is the purpose of a container who can't style it's content?
""::slotted() should full support complex selector"" has came up multiple time and always get closed without any solution.
""::slotted() should full support complex selector"" has came up multiple time and always get closed without any solution.
That should be tracked in a new issue, not in this old issue about ::slotted pseudo element. Also, supporting complex selector inside ::slotted would be about matching selector in the tree in which slotted node appears, not about selecting arbitrary descendant of slotted content. Regardless, you should file a new issue. We can't tack every new idea into an existing issue.
What a disappointing arbitrary limitation. Let the browser-makers solve performance issues and write the spec to be ideal. WEAK!
@Lonniebiz I’m not sure this is as arbitrary as it seems at first. If I’ve understood right, the performance cost stems from a mathematical truth rather than browser implementation details. (Correct me if I’m mistaken.)