- From: Tab Atkins Jr. <jackalmage@gmail.com>
- Date: Thu, 19 Sep 2013 16:09:04 -0700
- To: Dimitri Glazkov <dglazkov@google.com>
- Cc: public-webapps <public-webapps@w3.org>, Steve Orvell <sorvell@google.com>, Scott Miles <sjmiles@google.com>, Blake Kaplan <mrbkap@mozilla.com>, Elliott Sprehn <esprehn@gmail.com>, Dominic Cooney <dominicc@google.com>, William Chen <wchen@mozilla.com>, fantasai <fantasai@inkedblade.net>, David Baron <dbaron@dbaron.org>
On Mon, Sep 9, 2013 at 4:32 PM, Dimitri Glazkov <dglazkov@google.com> wrote: > Part 1: Revenge of the :host > > Turns out, it's bad to be Super Man. After the Shadow DOM meetup, > where we decided that shadow host could be matched by both outer and > inner trees (http://lists.w3.org/Archives/Public/public-webapps/2013AprJun/0985.html, > first point), we quickly coded this up in Blink and gave it to Mikey > ...erm, the Polymer folks to chew on. > > The folks spat out that morsel right across the table > (https://www.w3.org/Bugs/Public/show_bug.cgi?id=22980), and presented > good arguments to justify their etiquette faux pas. > > For what it's worth, it would be fairly easy to make shadow tree rules > match shadow host only when ":host" is present in a rule. > > Unfortunately, this would leave Tab (and other CSS WG folks) in a sad > state, since addressing these arguments makes it harder to keep a > straight face with the concept of a pseudo class in regard to :host. > See discussion on bug for the gory details. > > As of now, we are in that angsty state of not knowing what to do next. > Any ideas are appreciated. Note that there are some well-established > concepts in CSS and inventing fewer new concepts is much preferred. > Reuse, reduce, recycle. Some in-person discussion led to an elegant solution: keep the host element in the set of elements, but neuter all of its features. As far as the selectors in the shadow root can see, it's a node with no tagname, no id, no classes, etc. The one and only thing that will match it is :host and :host(). (And *, of course.) Also, just in case it wasn't clear earlier, :host() only matches the host element. Like :drop/:drop(), the non-function version is just the "widest possible" version of the functional version - it always matches the host, while ":host(sel)" only matches the host if something in the ancestor tree matches "sel". Here's an example: <div class="foo"> <x-dialog> [shadow-root] <div class="bar">some text!</div> <style> div { ... } // matches the div.bar :host { ... } // matches the x-dialog x-dialog { ... } // matches nothing... // there's no node named "x-dialog" viewable from here </style> </x-dialog> </div> > Part 2: Party ::part part > > Another possible wrinkle is the ::part pseudo element. After also > chewing on ::part for a little while, our brave guinea pi.. erm, > people also declared it to be tasting somewhat bitter. > > The best symptom can be seen here: > https://www.w3.org/Bugs/Public/show_bug.cgi?id=23162. When explained > that you would just chain x-nurk::part(woot)::part(zorp)::part(bler) > to cross each shadow tree boundary, the guinea people looked at me > like this: <_<. Then they pointed out that this both: > > a) implies ever-growing "part" API for each component, which will > quickly lead to the anti-pattern of developers simply declaring all > elements in their shadow tree as parts, and > > b) just looks ugly and constipated. > > Agitated shouts of "Y U NO LET US JUS DO EET" were echoing across the > San Francisco Bay, frightening America's Cup spectators. > > To calm the brave guinea people down, I showed them a magic trick. Out > of my sleeve, I pulled out two new combinators: A hat (^) and a cat > (^^). > > You would use them instead of ::part. The hat is generally equivalent > to a descendant combinator, except it crosses 1 (one) shadow tree > boundary (from shadow host to shadow root). The cat is similar, except > it crosses any number of boundaries. So, to target "bler" in the > previous part-y chain could be written as simply as > x-nurk^^[part=bler] or x-nurk^^#bler if ids are used instead of > part="bler" attribute. Respectively, you would target "woot" as simply > x-nurk^#woot. > > But wait there's more: you could use these new combinators in > querySelector, I proclaimed! In the nascent shadow DOM code, we > already started seeing the blood-curling > document.querySelector('x-nurk').shadowRoot.querySelector('#woot').shadowRoot.querySelector('#zorp') > chains of hell -- a problem that these new combinators would solve. > > Think of them simply general combinators that opens shadow trees for > selector traversal, just like Element.shadowRoot did for DOM > traversal. > > The brave guinea people became content and reverted to their natural > behaviors, but I then started worrying. Did I over-promise and finally > ruined encapsulation? When will our styling woes finally converge into > one solution? > > Luckily, I have you, my glorious WebApp-erators. Put on your thinking > hats and help find one uniform solution. Something that fits well into > CSS, doesn't add too many new moving parts, and keeps the brave guinea > people at bay. That'll be the day. In-person discussion convinced me of the use of this. Basically, we should go ahead and expose a nice, wide feature now, rather than trying to expose one that is locked down *just right*. We can add more features that are harder to misuse in the future, once we have a better idea of the common usage patterns. So, to be clearer, we'd be adding two new combinators, "^" and "^^". "^", the shadow combinator (or "hat"), pierces the upper-boundary encapsulation of a shadow root. The LHS has to be a component, something with an actual shadow root. "^^", the "all shadows" combinator (or "cat", or "double-hat"), is identical, but it pierces *all* shadow root upper boundaries. Here's another example: <div class="foo"> <style> x-dialog ^ .bar { ... } // matches x-dialog ^^ .bar { ... } // matches x-dialog ^ .baz { ... } // doesn't match - behind a second SR boundary x-dialog ^ x-button ^ .baz { ... } // matches x-dialog ^^ .baz { ... } // matches .foo ^^ .baz { ... } // doesn't match - div.foo has no SR </style> <x-dialog> [shadow-root] <div class="bar">some text!</div> <style> x-button ^ .baz { ... } // matches x-button ^^ .baz { ... } // matches </style> <x-button> [shadow-root] <div class="baz">more text!</div> </x-button> </x-dialog> </div> Tangentially related to this, it came up that several of these use-cases want to be able to target an element that is a direct child of a shadow root, but there's no way to indicate that in selectors currently. Similar things have come up in other contexts, such as running .query() on a DocumentFragment. The CSSWG has consistently refused to expand the meaning of :root, so we figured we could just introduce another pseudo-class called :top or something, which matches any element whose parent is not an element. ~TJ
Received on Thursday, 19 September 2013 23:09:52 UTC