Re: ::Parts of cats and hats everywhere, slashed by shadow

On Feb 7, 2014, at 3:39 PM, Daniel Buchner <daniel@mozilla.com> wrote:

> 
> 
> On Fri, Feb 7, 2014 at 2:31 PM, Linss, Peter <peter.linss@hp.com> wrote:
> 
> On Feb 7, 2014, at 9:43 AM, Daniel Buchner wrote:
> 
>> 
>> Sure it's a tad long - but you're a champ, you'll deal.
>> 
>> Yesterday a group of folks from this thread convened for a face-to-face meeting. I'd like to summarize the discussion, review our options, and present why I believe the proposal we zeroed in on during our meeting is the correct one:
>> 
>> A little history from the other side of the shadow coin --> the JS DOM. A long time ago in a galaxy far away, there was a feeling we should security-encapsulate Shadow DOM - it was a noble pursuit, a courageous endeavor. After a few cycles with the specs it became imminently clear that security-encapsulation of Shadow DOM is fraught with significant problems, and the added constraints only made possible a small number of all total use-cases. As a result, the decision was made to instead provide a flavor of encapsulation that shielded non-explicit Shadow DOM access and style overwriting. This form of encapsulation covers the vast majority of use-cases - primarily the desire for devs to create custom elements that provide a stable interface/render that isn't corrupted by unintended DOM manipulation and style leakage. However, an important allowance was the ability for component consumers to explicitly access the Shadow DOM via the shadowRoot property. This provided a way for developers to knowingly, explicitly reach into a component and manipulate its DOM - something that is often essential for consumers of third-party code.
>> 
>> Why talk about the JavaScript interface portion of Shadow DOM in a debate over a style issue? Because new web platform technologies that introduce APIs across layers of the stack are usually at their best when they are symmetrical, predictable, and familiar.
>> 
>> Let's take a look at the three proposals for styling elements in the Shadow DOM --> ::part, cat/hat (^^/^), and an extensible combinator + shadow token (/shadow)
>> 
>> 1) We should ::part ways
>> 
>> On its face, the notion of hoisting specific elements into CSS user-space seems like a good idea. You give component developers an explicit API for exposing named pieces of encapsulated shadow elements, and users get meaningful names to use in styling those elements. Unfortunately, this idea introduces a few major issues:
>> The component author is tasked with explicitly marking elements within their component they wish to expose for styling
> This system could just as easily be opt-in vs. opt-out.
> 
> It's not opt-out if you block explicit attempts to style by CSS selector instead of author-named token.

I don't follow what you're getting at in that sentence.

What I meant in my previous reply was that the system could expose all component pieces by default or hide them all by default, allowing the component creator to have to opt-in explicitly or opt-out explicitly. While I have my personal preference, it's completely orthogonal the mechanism used to select the pieces.

> If your point is that it can be opt-out because we could do both...then...err..agreed? (I don't personally care if we enable both, as long as we don't block component consumers from explicitly applying styles to unnamed/tokenized shadowed elements)
> 
> 
>> As a component consumer, you must know and use the special name for each element the component author marks
> 
> The component consumer always has to know the names and structure of the internal elements of a component in order to style them, no? What's the difference if those are pseudo-element names or actual element names?
> 
> ::part requires you to understand the whole ::part system, find the token names, and use the right ones for each component - cat/hat or / + shadow requires you to know one token that permits explicit access, and from there you need only open your developer console to find what to style.

If you're presuming using a developer console to peek inside the component to see how to style it in the first place, then there's absolutely no reason why the same tool can't show you whatever you need to know, be those element names, classes, attributes, or component author chosen pseudo-element names. This is a specious argument.

For the record, my proposal also explicitly stated that the default pseudo-element name for each exposed piece would simply be the element name. I merely offered a way for the component author to override that name where it makes sense to do so.
>> If the component developer forgets or fails to provide a token for a particular shadowed element, third-party developers are left without any easy path to accomplish their styling goals
> 
> There's also the counter view that a component developer may have a very good reason for _not_ allowing styling of a particular element. And that applying external styles can just as easily break components in any case.
> 
> That's true, this is precisely what the default barrier requires the component consumer to explicitly intend to style the shadowed elements of a thing (this is symmetrically to the JS DOM side - blocked by default, with a requirement for explicit consumer action to access) 

Fine, I've already said several times that the JS API and selector mechanisms should have a parallel behavior.

>> In real world use, shadowed element tokens become numerous, verbose, and crufty.
> Citation needed.
> 
> Not really, take a look a the long list of token names already in-play for things like form controls. To this you may reply: "Well look, it's working for those elements, that's a great reason to use them!", to which I will reply: "Those elements were debated by hundreds (if not thousands) of people, and the exposed shadowed elements they contained were painstakingly codified into token names - does anyone honestly believe web-at-large component authors are going to spend literally *years* to ensure they offer just the right elements to be styled?"

If you're talking about components that will eventually be folded into the platform, then yes, I see no reason why there wouldn't be years of experience behind carefully considered and experimented with naming conventions. That's generally the way we do this.

If you're talking about random one-off components, then they're going to be what they're going to be. Some will be clean and elegant, some will be a hot mess. This is the same whether their innards are expressed as element selectors, class selectors, attribute selectors, or pseudo-element selectors. I still don't see any justification for declaring that component author chosen pseudo-element names, where used, will be any more numerous, verbose, or crufty, than element names or class names.

In fact, by giving component authors an explicit mechanism to allow their component to be styled, I expect most authors will take a moment to try to come up with something reasonable, which will likely be more concise and understandable than whatever dom tree they happened to wind up with the get their desired effects, and the result will make more sense to the author using the component. e.g. "x-foo ::logically-named-thing" vs "x-foo ^ div span:nth-child(2)" which has no semantic value. Which of those is more verbose and crufty?

>  
> 
>> Assessment: this proposal requires writing selectors that are not familiar, using tokens that are unpredictable, and it is certainly not symmetrical to the JS DOM encapsulation paradigm.
> 
> I don't see how this assessment follows from the facts.
> 
> Using the same CSS selector/rule concepts you're used to (plus 1 combinator token), is far more familiar to current web developers than a rigidly enforced system featuring a better-hope-the-author-thought-to-name-it-for-you constraint and a component-specific named token DSL.

Again, my proposal didn't require the component author to name the piece, merely that they chose to expose it (or failed to chose to hide it, depending on what the default behavior is).

>> 
>> 
>> 2) Hats ^, and cats ^^, and bears - oh my!
>> 
>> Cat-hats are on the right track. This idea turns (correctly) toward a more open and permissive model. Moving to a known combinator allows component consumers to explicitly, with intention, style anything in the Shadow DOM. This means component consumers are no longer left to hope that authors provide the styling hooks they need. It also removes the need to litter CSS code with shadow element tokens. In addition, component consumers are still able to style shadowed elements in a more familiar way. Awesome, problem solved!...close, but no cigar. Here's what this option leaves to be desired:
>> It introduces YAACs (Yet Another ASCII Character) - pretty soon we'll need a periodic table to remember them all
>> YAACs are as good as klingon to novice developers - shouldn't we be more obvious if we can?
> 
> This also requires educating authors about just what it means to pierce a shadow boundary (including what a shadow boundary _is_). This may seem familiar and obvious to people who have been living with the internals of shadow dom for years, it is something _entirely_ new to the general web author who just wants to make part of a widget blue.
> 
> Sure, but with /shadow, only once. After they know how to access the shadowed elements, developers will read the docs for the component they are using (which will tell them about friendly class/attribute-tagged elements), or simply style shadowed elements in accordance with their needs. In many cases, the author's class/attribute tagging will be enough, but for many other component consumers, it won't - let's not tarnish the latter to polish the former.

How is expecting the user to read the docs to find a friendly class name any less of a burden than reading the docs to find the friendly pseudo-element name?
>> Assessment: this proposal is pretty darn close - it allows the use of familiar looking selectors, it's predictable once you understand the combinator, and symmetrical to the JS DOM encapsulation paradigm.
>> 
>> Example: x-foo ^ div
>> 
>> 
>> 3) /shadow games FTW!
>> 
>> An extensible combinator is the gift that keeps on giving. With an extensible combinator (ex: / + a token) we can define tokens like shadow, and shadow-all, to enable the styling of shadowed elements. The best part is we can introduce other tokens in the future without YAACing on our shoes. This proposal brings with it all the positives that hat-wearing cats deliver, without the downside of two new, non-obvious, ASCII combinators that are hard-bound to a specific DOM API. The only negative I can think of currently:
>> /shadow is longer than ^
>> Assessment: this proposal hits on all cylinders - it allows users to write familiar selectors without knowing one-off token names,
> 
> The internal names and structure of the components are still one-offs, aren't they? by definition? I don't see how selecting the internals of something just invented can be considered familiar.
> 
> Technically yes - but under this proposal you need not understand a ::part system to distinguish which elements you have access to, you need only inspect the shadowed elements and use 'normal' CSS selectors (with /shadow in your selector string) to style target elements.

Two points, firstly, I think you're conflating my proposal with someone else's. To be clear, again, my proposal is that instead of a special combinator (regardless of the combinator's syntax), the exposed pieces of a component are simply addressed as pseudo-elements, not a special pseudo-element-that's-really-a-combinator thing, just pseudo-elements. So by default instead of:
x-foo ^ div { ... }
you have:
x-foo ::div { ... }
(or possibly x-foo::div { ... }, there's a subtlety here that Tab and I have been discussing, and I now understand the point he was trying to make better, I think we can resolve that, but that's a slightly separate issue and we'll take that to a different thread if it's worth pursuing)

Layering on top of that, I proposed an optional mechanism for component authors to override the piece's pseudo-element name, where that makes sense to do so, and a mechanism to opt-in or opt-out of exposing given pieces (which doesn't care if the default behavior is exposed or private). The next layer on top of that was a proposal to define a separate mapping mechanism between the pseudo-element names and the pieces (which I agreed should be deferred to a future level).

My proposal has no "::part" or "::part()" thing, just pseudo-elements, which _are_ normal CSS selectors (I did propose relaxing the current syntactical restrictions on the use of pseudo-element selectors though, which has other applications and use cases beyond this).

Secondly, reading your message that started this thread and your later reply, I'm seeing it as someone who has reached a conclusion and is now just arguing to defend it (particularly by repeatedly mischaracterizing my proposal, but maybe that's because I failed to explain myself clearly enough). Not someone who is interested in having a conversation about a technical matter and is willing to consider other viewpoints. I don't know you personally so maybe I'm just misreading the tone (which frankly comes across as condescending), and apologies if I did, but it doesn't strike me as an effective way to build consensus. Let's try to be a bit more constructive here.


Peter

Received on Saturday, 8 February 2014 01:33:42 UTC