WICG / webcomponents

Web Components specifications
Other
4.36k stars 370 forks source link

Styling of elements where attachShadow(...) not allowed #376

Closed nazar-pc closed 8 years ago

nazar-pc commented 8 years ago

Question started in #110, which is related, but since #110 is closed now, better move conversation here. The main issue is that after /deep/ was deprecated and some native elements are disallowed to have Shadow Root it becomes practically impossible to extend those native elements, because styling is one of the key features during button, progress or input extension.

There was few ideas in comments of linked issue, but the last (which is a compromise to avoid complicating things too much) is to state in specification something like following:

Shadow Root in following elements _list_of_elementshere MUST contain <shadow></shadow> in the root and MAY contain any number of <style>...</style> elements for styling purposes, any other elements are NOT allowed.

_list_of_elements_here_ is basically blocklist of elements where atttachShadow(...) was not allowed. Effectively this only allows to inherit native Shadow DOM entirely and only add some styling to it.

Hopefully, some solution will be found till v1 release, re-implementing native semantic and work on accessibility for those elements is tricky, there should be a way to inherit all that goodness.

hayatoito commented 8 years ago

That seems what we tried to achieve in the era of v0 spec, but I regret to say that we have failed to define the well-defined rendering behavior of native elements if they are used in such a way.

See https://www.w3.org/TR/2014/WD-shadow-dom-20140617/#html-elements-and-their-shadow-trees as the historical record.

nazar-pc commented 8 years ago

Can you also point to some discussion where blocking issues regarding that approach are listed?

hayatoito commented 8 years ago

The following might be helpful for you to understand the problem space: https://code.google.com/p/chromium/issues/detail?id=234020 Note that supporting styling of native elements was not our primary goal there. The approach might be similar, but the goal could be different.

Regarding with the discussion about the spec itself, it is difficult for me to point any useful discussion. I guess that's because this approach has not gotten much attention from folks. If someone knows some discussion we can point, please tell us here.

annevk commented 8 years ago

Basically we need to advance https://github.com/domenic/html-as-custom-elements somehow to figure out what we can do here.

nazar-pc commented 8 years ago

I've seen https://github.com/domenic/html-as-custom-elements a long time ago already. It tries to tackle an issue fundamentally, which is definitely a bright happy (and far) future, but I have a feeling that most folks don't need it (at least initially).

What most of times people want to have is:

This is the reason I decided to boil down the whole issue to just styling alone. Strictly speaking it works like style attribute, but allows to use attributes selectors, pseudo-elements, pseudo-classes and other features like in regular CSS applied to this element (which is currently only doable with html /deep/ element).

Anytime in future when working with custom Shadow Roots on those elements is defined it will be possible to allow more than <style> and <shadow> elements without breaking backward compatibility. Let's assume UA Shadow Root as black box for now and just inherit as indivisible whole thing.

annevk commented 8 years ago

So the reason you want to attach a shadow root is to attach styles to the host element? You don't care about the shadow tree? Is there no simpler way to do that? @tabatkins?

nazar-pc commented 8 years ago

Exactly (except for button which works in Chromium right now, but in blocklist for v1).

Custom progress element as one of the simplest examples: styling and scripting For buttons and inputs it is a bit more complex.

hayatoito commented 8 years ago

You might be also interested in https://github.com/w3c/webcomponents/issues/300 for styling.

I do not think attaching a shadow root to a native element does not solve a styling issue (from outside) nicely.

nazar-pc commented 8 years ago

I agree, mentioned proposal is great, but this issue is specifically about internal styling of element, possibility to extend native element and give it different, let's say, default styling.

Here is an example: 2016-02-02 13-40-47 And source code for this part, where first half are extended elements with multiple improvements and default styling, while second half are raw native elements as they are (Chromium):

<button icon="home" is="cs-button" type="button">Button</button>
<input is="cs-input-text" type="text">
<input disabled is="cs-input-text" type="text">
<button force-fullsize icon="home" is="cs-button" type="button"></button>
<cs-icon icon="home"></cs-icon>
<textarea is="cs-textarea"></textarea>
<nav is="cs-nav-tabs">
    <button is="cs-button" type="button">One</button>
    <button is="cs-button" type="button">Two</button>
</nav>
<section is="cs-section-switcher">
    <article>One</article>
    <article>Two</article>
</section>
<label is="cs-label-switcher">
    <input checked type="radio" value="0"> Zero
</label>
<label is="cs-label-switcher">
    <input checked type="radio" value="1"> One
</label>
<nav is="cs-nav-pagination" page="1" pages="20"></nav>
<progress is="cs-progress" value="20"></progress>
<br>
<br>
<button icon="home" type="button">Button</button>
<input type="text">
<input disabled type="text">
<button force-fullsize icon="home" type="button"></button>
<cs-icon></cs-icon>
<textarea></textarea>
<nav>
    <button type="button">One</button>
    <button type="button">Two</button>
</nav>
<section>
    <article>One</article>
    <article>Two</article>
</section>
<label>
    <input checked type="radio" value="0"> Zero
</label>
<label>
    <input checked type="radio" value="1"> One
</label>
<nav page="1" pages="20"></nav>
<progress value="20"></progress>

As you can see, it is very convenient to be able to greatly improve native element with [is] while preserving its semantics and accessibility features. I'm trying to always extend native elements in contrast to Polymer team, they try to re-implement all the elements from scratch

hayatoito commented 8 years ago

Thank you for sharing it. I guess you are using type extension. https://w3c.github.io/webcomponents/spec/custom/#dfn-type-extension

AFAIK, we cannot style internal of elements even if we use type extension. A type-extension just acts as label so that we can style elements with the label from outside, right?

Thus, backing to the proposed approach:

Shadow Root in following elements _list_of_elementshere MUST contain in the root and MAY contain any number of elements for styling purposes, any other elements are NOT allowed.

I am wondering how this works and what is the expected behavior. Could you tell us the concrete example how it should work?

nazar-pc commented 8 years ago

Yes, I'm using type extension.

By internal styling I meant element itself, nothing deeper than it is available from outside.

If you don't mind I'll give Polymer example:

<dom-module id="cs-input-text">
    <template>
        <style>
            :host {
                border : 10px solid black;
                color  : red;
            }

            :host([disabled]) {
                color : blue;
            }

            :host([compact]) {
                width : auto;
            }

            :host([full-width]) {
                width : 100%;
            }
        </style>
        <shadow></shadow>
    </template>
    <script>
        Polymer({
            is      : 'cs-input-text',
            extends : 'input'
        });
    </script>
</dom-module>
<!-- usage -->
<input is="cs-input-text">
<input is="cs-input-text" disabled>
<input is="cs-input-text" disabled compact>
<input is="cs-input-text" full-width>

Shadow Root of input[is=cs-input-text] will contain UA's Shadow Root without any changes + <style> element to give element additional default styling. Other elements than <style> MUST be forbidden till future versions of spec which will define how it works.

hayatoito commented 8 years ago

Thank you. Maybe I misunderstood the concept of "internal styling". To me, it looks "styling from outside by default". :)

Having said that, I still do not think it is a good idea to use attechShadow() for this purpose. Can we have a more lightweight approach?, such as

document.registerDefaultStyle("input", condition, style) or something?

nazar-pc commented 8 years ago

To me, it looks "styling from outside by default". :)

Exactly

I have nothing against any alternative approach, the main point just to make this possible.

I do not personally like using imperative syntax for styling purposes, there should be a way to use <style> nodes for this. Maybe introduce something like Style Root that can only contain CSS? This would help to avoid any ambiguity.

...
createdCallback : function () {
    var s = document.querySelector('style#something');
    this.attachStyle(s); // and/or this.createStyleRoot()
}
...
hayatoito commented 8 years ago

Thanks. BTW, one of the primary reasons we removed /deep/ is it's too powerful and it's very style-engine unfriendly combinator in terms of the performance.

If we are allowed to ban a combinator, we could have the following declarative rules without significant performance penalty:

@global-compound-selector-rule {
 /* This rule applies to any element, even if it is in a descendant shadow tree.
  However, we are not allowed to use any combinator in a selector here. */
 input {
     border : 10px solid black;
     color  : red;
 }

 input([disabled]) {
     color : blue;
 }

 input([compact]) {
     width : auto;
 }

 input([full-width]) {
     width : 100%;
  }
}

Just as a naive idea.

hayatoito commented 8 years ago

Let me close this issue tentatively. Please feel free to re-open this if someone still wants to support this use case.

rniwa commented 8 years ago

We're having a hard time following this discussion because there is a lot of different use cases and ideas being discussed here. Could someone compile a list of concrete use cases that are meant to be addressed by this issue?

domenic commented 8 years ago

@rniwa are you referring to #468? This discussion was closed and its use case remains unaddressed I believe, or rather the specs have evolved significantly so that it's not very applicable.

rniwa commented 8 years ago

Oh oops, yeah.

nazar-pc commented 8 years ago

Actually the idea was to be able to somehow style elements that extend native ones (type extension if spec didn't change in this respect) because of Shadow Root absence on those and #468 actually covers this use case. So I'm completely satisfied with approaches in #468 and don't need this to be reopened.

rniwa commented 8 years ago

Since we're opposing to having type extensions (is attribute, etc...) in custom elements so the approach depicted in the issue #468 would not work for builtin elements that do not support shadow roots.

nazar-pc commented 8 years ago

Do you mean it will not be supported at all? Where can I find discussion or anything about it?

rniwa commented 8 years ago

Custom elements will be supported but only for ones that don't extend subclasses of HTMLElement. See http://www.w3.org/2016/04/05-webapps-minutes.html We opposed but I guess the working group's consensus to keep it in the draft until it becomes clear that the feature won't be implemented by all major browser vendors even though we've already said so (i.e. don't support it).

nazar-pc commented 8 years ago

Haven't found what you said following the link.

This would be very frustrating if not implemented at all.

As developer who is using Polymer and Shadow DOM (native in Chrome, full polyfill in other browsers) I do not see any sane reason to re-implement, say, input[type=password] or button[type=submit] if it is already present in browser and contains all semantic and accessibility features out of the box. I want just style it a bit, add few methods and events. I'm not intending to change UA Shadow Root or something like this.

The same about progress - all I need is to set max=100 by default and apply default styling I need to element itself (:host). Why should this require me to implement element from scratch?

rniwa commented 8 years ago

See https://github.com/w3c/webcomponents/issues/133, https://github.com/w3c/webcomponents/issues/363, and https://wiki.whatwg.org/wiki/Custom_Elements#Subclassing_existing_elements

nazar-pc commented 8 years ago

I see valid points in wiki, but IMO how it works in Chrome now is perfectly fine as for initial implementation. It doesn't scale, this is true, it doesn't give any access to UA Shadow DOM, but it gives some benefits inaccessible otherwise as well.

Rebuilding native elements as custom elements is perfect idea and I really hope we'll be there some day, but it feels like it may take 5+ years until it will be available for developers, however type extension already works in Chrome and it even works reasonably well with polyfill.