Skip to content

[css-shadow-parts] consider putting more power on user instead of author #2963

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

Closed
lifaon74 opened this issue Jul 30, 2018 · 7 comments
Closed

Comments

@lifaon74
Copy link

lifaon74 commented Jul 30, 2018

The current spec is centered around the lib (custom element) author, but doesn't really thing about the users (developers which use the custom element) and its limitations. If the author of a custom element doesn't include part attributes the element won't be able to be themed even in legit situations (like a font size or a color, from a charts lib).
This get even worse for nested custom elements from different authors... (like an input from author A which use a datepicker from author B). In real situation the custom element nesting may be often greater than 10. One missing part attribute could be dramatic.
Moreover, in enterprise, we deal a lot with legacy or 'closed' code. We could be forced to theme an unmaintened custom element without part (some libs are maintained 'only' 1 year... where legacy code could last 10 years, sad reality of the vast majority of companies...) or to theme a 'closed' code (like a paying charts lib, where pull requests are impossible).

All of this shows us that the power should be in the hands of the user (here the developer) instead of the author. Users represent far more people than authors (a custom element developed by one guy could be used by millions).

From the specs:

The previous proposed method for styling inside the shadow tree, the >>> combinator, turned out to be too powerful for its own good; it exposed too much of a component’s internal structure to scrutiny, defeating some of the encapsulation benefits that using Shadow DOM brings.

I found it pretty damn wrong. Developers are grown people ! They have and want powerful tools and are perfectly able to use them safely. We could all postfix css rules with !important but we won't do it because we all know it should be used with caution. The reality shows us that as some point we strongly need power.

All of this to say : what about re-introducing the /deep/ operator ? Or a least some equivalent from the css shadow parts that allow user (the user of the lib (custom element)) to force deep shadow piecing for some critical situations were no other choice is possible. For me the current css shadow parts is too much centered around the author which have final decision to put part, where the real need is for users.

Feel free to comment and to propose solutions, the discussion is open.

PS: to be absolutely clear, here the term 'user' represents the developers which use custom elements (shadow element) from other developers (called 'authors').

@idoros
Copy link

idoros commented Jul 30, 2018

From the perspective of the component author, The ability to define a style API (whatever that ends up being) is important in order to handle component versioning over time.

And while I think code that guides developers on how to use it correctly, as intended by the author, is incredibly important, and should be the default mode, I agree that there should be a way to opt-out when needed to. A way to "dangerously" pass the shadow boundary would be helpful at certain times.

@tabatkins
Copy link
Member

We tried the deep combinator; what it ended up with in practice (that is, based on experience from real developers writing real code with it) was fragile and error-prone code. You end up losing the nice "I know exactly what I'm targetting" quality that shadow DOM's encapsulation is supposed to provide, because you can write a rule deep-targetting a particular class you know about, and accidentally hit other components that happen to use that same class internally, which isn't a detail you should normally need to worry about. And that's not even getting into the fact that you're now relying directly on internal structure of things that you aren't supposed to care too much about the internal structure of, so any updates to the component are likely to break your code.

Switching to ::part means that component authors get to publish a reliable, stable styling API that's robust to changes they make in the future, and they aren't exposing more details than necessary about the internal state of their component. For component users, it means that they know exactly what's safe to target, and it's completely impossible to accidentally over-target unrelated elements in other components.

This is more limited, yes, but this is the level of limitation that appears to hit the sweet spot. It's intentionally very similar to any class-based programming language using private state, or JS using closure-variables, to hide internal variables from outside code - if you have to reach into the internals of a class, either you're doing something very wrong, or the class author wrote a bad API for their class.

@lifaon74
Copy link
Author

lifaon74 commented Aug 1, 2018

We tried the deep combinator; what it ended up with in practice (that is, based on experience from real developers writing real code with it) was fragile and error-prone code. You end up losing the nice "I know exactly what I'm targetting" quality that shadow DOM's encapsulation is supposed to provide, because you can write a rule deep-targetting a particular class you know about, and accidentally hit other components that happen to use that same class internally, which isn't a detail you should normally need to worry about.

Well maybe because developers didn't understood to use with parsimony the deep operator... it was new and experimental. The "it's dangerous" is for me a fake argument. After all, I could write a while(true); or doing some * { color: red }. It provides big power because we need it sometimes, this doesn't mean it is necessary to be used.

The big problem: you assume that the shadow component will be perfect (inclues @apply, and part, etc...), maintained for a long period and all the users of the lib will update all these components when a new release is here. BUT in practice, when you work in company, you deal most of the time with legacy code where no libs are updated for years (or not updatable because the old code doesn't support it), most of them are unmaintened anymore or the code is "closed" which mean no pull requests, so no changes are possible to fix the bugs/missing parts (here css theming). That's for this kind of really frequent situations (except maybe if you work at google or microsoft), that we need some power to bypass the restrictions of shadow dom. I anticipate a big problem that we'll all face in a not so long future. Here you thing as a pure developer, not as a businessman which face every time crazy clients' requests that you need to satisfy !

And that's not even getting into the fact that you're now relying directly on internal structure of things that you aren't supposed to care too much about the internal structure of, so any updates to the component are likely to break your code.

Wrong ! I care a lot because I want to theme with precision a component (like the icon of a pause button from a video player that a client request me to change). If the author forgot to put a variable for a background-image (or that I want to add the property), I want to be able to bypass the shadow dom boundaries. Moreover, If I see any breaking changes in the display, I can rollback the update (or avoid major update), or adapt my code. BUT I won't be able to adapt the lib's author code... because of the current limitation.

Switching to ::part means that component authors get to publish a reliable, stable styling API that's robust to changes they make in the future, and they aren't exposing more details than necessary about the internal state of their component.

Something that never append in reality, libs evolves so fast that major updates (including breaking changes) append faster than bugs fixes sometimes. Moreover, a client may absolutely want to incorporate a shadow component from a "closed" code company (ex: a solidwork preview component). In this case, you probably won't see any part or css variables... so you're deeply fu***.

For component users, it means that they know exactly what's safe to target, and it's completely impossible to accidentally over-target unrelated elements in other components.

This is another fake argument: To be completely safe, just don't use deep...

What's you're saying is basically: you see when you have sex, you can get HIV so we'll force you to use a condom no matter's what (here the removal of the deep operator). It's in steal and totally unbreakable. You want kids (power to theme, bypass) ? Sadly we won't allow you to remove the condom, so sorry it's impossible... (I didn't find a better representation sorry :) )

or the class author wrote a bad API for their class.

This is exactly what appends in 99% of the cases. At first it's good until technologies evolves, code is unmaintened or provided from a closed source... And sadly when you work in a company, you don't always have choice to use the lib you want, and to maintain frequently your code.

Finally, don't assume that I say: "everybody should use deep, it's no cool !!!!" What i mean is: you probably don't need deep and should avoid it, BUT if you're stuck with a shadow component without css variables and no way to update the lib's code AND you absolutely need to theme it, you should have a way to to it ! This situation won't appear immediately, as shadow dom is pretty new but probably in 6 months / 1 year we'll start to encounter frequently this kind of problem. Where the simple introduction of a small word deep could solve easily all of this problems...

@lifaon74
Copy link
Author

lifaon74 commented Aug 1, 2018

Could you consider putting this discussion as opened as only 3 person participate ?

@tabatkins
Copy link
Member

Setting aside oddities like #define private public;, the notion of encapsulation boundaries and information-hiding is an idea with literally decades of research and practice behind it; it's present in every language. It was the entire basis of the Shadow DOM feature in the first place, and even having shadows be accessible at all was a pretty vigorous debate (leading to the current compromise of no default, so you have to specify whether your shadow is "open" or "closed" whenever you construct it).

When those classes are badly designed, they can be annoying to work with, sure. But the answer isn't to work around the language's info-hiding and poke into the class (and it's actually impossible to do so in many languages, including JS), it's to get the class fixed to fit your needs.

Could you consider putting this discussion as opened as only 3 person participate ?

I closed this issue because this debate isn't new; it's retreading ground that we went over years ago, tried out, and realized our mistakes about. The question is more-or-less settled at this point, with far more than three people having discussed it, including all the browser vendors, spec authors, and many real-world authors trialing the features in professional contexts over an extended period of time.

When we first designed the interaction of shadow DOM and selectors, we had a very locked-down feature similar to ::part. Early users complained about this and wanted more freedom, so we switched over to just using /deep/. The exact same users then complained that they were shooting themselves in the foot too much with /deep/, and were developing more constrained API shapes to protect themselves from it, ending up similar to ::part again.

At the same time, it turned out that /deep/ was expensive to implement as well, and we weren't coming up with any good ideas on how to make it cheaper without abandoning the entire "isolated styling world" idea altogether. (You end up having to copy all the /deep/-using rules into every descendant component's style, duplicating those rules many times over.) So abandoning it and returning to something more limited and well-defined was welcome on the performance side as well.

So this discussion will remain closed; without some surprising new piece of information (like browser vendors suddenly deciding that they actually really want to implement this), relitigating the issue won't change the result.

@lifaon74
Copy link
Author

lifaon74 commented Aug 2, 2018

So basically, the only proper solution here (when you work in a company vs indie projects) is to avoid shadow dom components or only to use the extremely reliable ones. It's sad because shadow elements are really great except for the impossibility to theme them from an external perspective...

The exact same users then complained that they were shooting themselves in the foot too much with /deep/, and were developing more constrained API shapes to protect themselves from it, ending up similar to ::part again.

Totally invalid argument ! As developers, we literally have god's power in the hands, we can design any apps we want without restrictions. Every developer could write a while(true) or really bad code. It's their responsibility only, not the responsibility of the language authors...

At the same time, it turned out that /deep/ was expensive to implement as well, and we weren't coming up with any good ideas on how to make it cheaper without abandoning the entire "isolated styling world" idea altogether. (You end up having to copy all the /deep/-using rules into every descendant component's style, duplicating those rules many times over.) So abandoning it and returning to something more limited and well-defined was welcome on the performance side as well.

I have seen this argument many times, so it seems to be the real reason and the most relevant. But still, not really true: the developer should limits its usage of deep for critical situations only, and he knows it will impact performances. So the deep could exists but be used with extreme precaution, and if developers want to use it because they're lazy and don't care of performances, it's their problems, not ours.

I closed this issue because this debate isn't new; it's retreading ground that we went over years ago, tried out, and realized our mistakes about. The question is more-or-less settled at this point, with far more than three people having discussed it, including all the browser vendors, spec authors, and many real-world authors trialing the features in professional contexts over an extended period of time.

Could you share please links ? Currently i have found only a few peoples involved which is far to represent the vast majority of developers...

@tabatkins
Copy link
Member

So basically, the only proper solution here (when you work in a company vs indie projects) is to avoid shadow dom components or only to use the extremely reliable ones. It's sad because shadow elements are really great except for the impossibility to theme them from an external perspective...

Use well-written components, or import them locally and tweak them yourself. Same as you have to do for JS libraries.

Totally invalid argument !

As a language designer, it's my responsibility to give people the power they need, but also prevent them, as much as possible, from shooting themselves in the foot with that power. JS doesn't let people access raw pointers, so you can't segfault a computer like you can in C. This is a limitation, but it's worthwhile.

(And note that there are languages that prevent infinite loops, like GLSL, but it's an annoying enough restriction that general-purpose programming languages have generally made the tradeoff that the possibility of infinite loops is worth the usefulness of unbounded looping constructs. It's always about tradeoffs, it's not a dogmatic "allow everything!" or "restrict everything!".)

I have seen this argument many times

Speculating about which argument is "real" is incorrect; I gave you the reasons, and this is one of them.

We make decisions not to adopt features that would be to slow to use all the time. When you give people a feature, they're going to want to use it, which just makes sense.

Could you share please links ?

Unfortunately, most of this conversation took place in person, or in Google Docs, etc. This was before we switched to using GitHub to track everything. However, you can find discussions about this by searching the old mailing list archive for "shadow DOM".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants