This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 22980 - [Shadow]: shadowRoot styles should not match the host element
Summary: [Shadow]: shadowRoot styles should not match the host element
Status: RESOLVED INVALID
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: HISTORICAL - Component Model (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Hayato Ito
QA Contact: public-webapps-bugzilla
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 23062
  Show dependency treegraph
 
Reported: 2013-08-16 02:03 UTC by Steve Orvell
Modified: 2014-03-10 07:57 UTC (History)
7 users (show)

See Also:


Attachments

Description Steve Orvell 2013-08-16 02:03:18 UTC
Currently selectors in shadowRoot styles match the host element. This makes it relatively easy to write rules that have unexpected, undesired effects. Consider a shadowRoot like this:

  <style>
    #thing {
      background: red;
    }
  </style>
  <div id="thing">sr-div</div>  

  The author has setup an id based style that should apply only within this shadowRoot. Now that shadowRoot is added to an element like this:

  <div id="#thing">host-div</div>
  
Now both host-div and inside-div will be styled via #thing which is not what the shadowRoot author wanted or expects.

To fix this, we can make the :host the only way to match the shadowRoot host element.
Comment 1 Dimitri Glazkov 2013-08-16 02:57:28 UTC
oy vey. Didn't we just all agree that it _should_ match? http://lists.w3.org/Archives/Public/public-webapps/2013AprJun/0985.html
Comment 2 Steve Orvell 2013-08-16 16:06:39 UTC
Yeah, we did agree that this should match (big sigh). I think that was a mistake and we now have a wart on an otherwise pretty face. I'd be happy to be convinced otherwise.

My main concern is that ShadowDOM authors will have to defend against accidentally having styles match host by not writing simple selectors. Imagine rules like this inside a shadowRoot style element. The author intends to match elements inside the shadowRoot:

  #container {
    border: 1px solid black;
  }

  .rounded {
    border-radius: 10px;
  }

If the host incidentally matches one of those selectors, things will blow up. To avoid this the ShadowDOM author is forced to always write:

:host #container {...}
:host .rounded {...}

That seems pretty unfortunate doesn't it? Am I missing a virtue of having these styles match the host element? It seems like we have the host element well covered via :host.
Comment 3 Dimitri Glazkov 2013-08-16 16:31:18 UTC
Tab, Hayato-san, Sakamoto-san, WDYT?
Comment 4 Tab Atkins Jr. 2013-08-16 17:03:20 UTC
There's no sane way to make host styleable only when you specifically want it without violating Selector semantics, as we found out earlier.  Saying that only :host can match a host element violates Selector semantics, because pseudo-classes are just impl-defined classes; that is, they merely filter the available elements, they don't add new elements to the set. :/
Comment 5 Steve Orvell 2013-08-20 17:08:20 UTC
Does this address the selector semantics concern?

1. the host element is in the set of elements that selectors in shadowRoot styles can match.
2. any selector that does not contain :host cannot match the host element.

If so, this gives us the best of both worlds, e.g.

#container, .rounded { 
  /* matches only elements inside shadowRoot, not the host element */
}
.rounded:host {
  /* matches only the host element if it has the `rounded` class */
}

.special:host > div {
  /* matches div children of the shadowRoot if the host element has a `special` class */
}
Comment 6 Tab Atkins Jr. 2013-08-20 18:23:18 UTC
(In reply to comment #5)
> Does this address the selector semantics concern?
> 
> 1. the host element is in the set of elements that selectors in shadowRoot
> styles can match.
> 2. any selector that does not contain :host cannot match the host element.

No, saying "X is in the set of elements, but it's impossible to select unless you tack this pseudo-class on" is identical to "using this pseudo-class adds X to the set of elements".  Selectors, pseudo-classes included, are just filters.  

Combinators transform the set of elements via whatever relation they define.  (Pseudo-elements are included in this, just with a syntax that's slightly different than other combinators.)

We tried to use a combinator to separate the host from the inner elements, but it was all terribly clumsy. :/
Comment 7 Dominic Cooney 2013-08-21 00:46:48 UTC
(In reply to comment #6)
> (In reply to comment #5)
> > Does this address the selector semantics concern?
> > 
> > 1. the host element is in the set of elements that selectors in shadowRoot
> > styles can match.
> > 2. any selector that does not contain :host cannot match the host element.
> 
> No, saying "X is in the set of elements, but it's impossible to select
> unless you tack this pseudo-class on" is identical to "using this
> pseudo-class adds X to the set of elements".  Selectors, pseudo-classes
> included, are just filters.  

Can't you add a layer of sugar? Host is in the set by default. In the (possibly unwriteable) primitives there's :except-host which removes host from the set.

In the sugared layer, every rule is desugared to add :except-host. Unless the rule contains :host. Then it the desugaring just removes :host (because it is not primitive syntax, because it violates those things you were worried about) and hence host remains in the set.
Comment 8 Tab Atkins Jr. 2013-08-21 14:22:31 UTC
(In reply to comment #7)
> Can't you add a layer of sugar? Host is in the set by default. In the
> (possibly unwriteable) primitives there's :except-host which removes host
> from the set.
> 
> In the sugared layer, every rule is desugared to add :except-host. Unless
> the rule contains :host. Then it the desugaring just removes :host (because
> it is not primitive syntax, because it violates those things you were
> worried about) and hence host remains in the set.

We don't desugar CSS yet (beyond conceptual explanations), so this probably won't fly.  Plus, it's just a way to pretend that we're not making :host magical. :/

Look, if this is *actually* something you want, then what you're doing is changing the context the selector is evaluated in.  That means removing the host from the set of elements normally, and having an at-rule - @host - which adds it back for its contained selectors.  (Or the other way around, obviously.)

Or, we can just assume that we'll actually add CSS Nesting at some point, and live with the fact that wrapping rules in an ":host {...}" will protect you:

:host {
  .foo { /* won't accidentally select the host */ }
  #bar { /* this either */ }
}
Comment 9 Dimitri Glazkov 2013-08-23 16:30:39 UTC
Sounds like there isn't an obvious and non-awkward solution. I'd hate to drag everyone back into another meeting, but this might be the best way to solve this expeditiously.
Comment 10 Hayato Ito 2013-08-26 08:29:55 UTC
I've just read the discussion.
I don't have any idea either. Let me sync up with @tasak for some ideas.
Comment 11 Steve Orvell 2013-08-26 19:03:33 UTC
Here is an example of why rules matching the host element is problematic (requires ShadowRoot enable browser, e.g. chrome):

http://jsbin.com/UgirokO/5/edit
Comment 12 Steve Orvell 2013-08-26 19:18:22 UTC
The above jsbin should be run in at least Chrome 30 (as of this writing, that's the Chrome Canary).
Comment 13 Steve Orvell 2013-08-26 19:20:15 UTC
Oops, sorry, the Experimental Web Platform features flag must also be enabled.
Comment 14 Ojan Vafai 2013-08-27 23:58:17 UTC
Speaking with my web developer hat on, I was very confused when the styles inside my shadow were leaking out into the host context. It defeats a lot of the point of trying to get isolation.

Maybe we need a different syntax than :host to keep CSS selector semantics happy, but the currently solution is worse than violating CSS selector semantics IMO.
Comment 15 Hayato Ito 2014-03-10 07:57:01 UTC
This discussion looks obsolete.
The style in shadow trees might match the host element, using ':host' pseudo classes. Let me close this bug.