- From: Tab Atkins Jr. <jackalmage@gmail.com>
- Date: Wed, 6 Mar 2013 15:03:23 -0800
- To: public-webapps <public-webapps@w3.org>
Today, the @host rule contains style rules, and changes the context that their selectors are processed in to be *solely* the host element of the component. In the recent meetup on our side, we discussed some limitations with this model, and ways to fix it. In particular: * it would be nice to be able to style the *contents* of the shadow DOM based on the host element. For example, switching between color themes based on an attribute put on the host element. * it would be nice to be able to style the host element based on its *surroundings* in the light DOM. For example, a component laying out differently when it finds itself in a nav list versus in the main content of a page. We came up with two changes to @host that would let us address these scenarios gracefully, one addition and one (breaking) change. First, the addition. This addresses the first bullet point. Currently, the spec already has a ::distributed() pseudo-element, which applies to <content> elements and takes a selector, applying it over the light-DOM elements distributed by that <content>. Analogously, we propose adding a ::shadow() element, which applies to host elements and takes a selector, applying it over the shadow DOM. This is only valid within @host, which is only valid within the component's own stylesheets - the outer page can't use it to arbitrarily target the component's shadow DOM. Second, the change. This addresses the second bullet point. We propose that the content in which selectors within @host are evaluated be widened to encompass the entire light DOM. The @host rule itself then invokes scoping rules, making all the selectors "scope-filtered" <http://dev.w3.org/csswg/selectors4/#scope-filtered> with the host as the scoping element. In other words, if you want to generically target the host element, just write "@host { :scope { ... } }". If you want to target the host based on an ancestor having class="foo", write "@host { .foo :scope { ... } }". If you want to target all the <li>s among the light-DOM descendants of the host, without a side trip through the shadow DOM and back with ::distributed, just write "@host { li { ... } }". (This last usage can in many cases be done with ::distributed(), possible in concert with ::shadow(), but our proposal makes the selectors much neater for this case, and actually allows some things that are impossible with ::distributed, like targeting all the even <li> elements in the light DOM regardless of which <content> elements picked them up.) This is a minor breaking change, because a rule like "@host { * { ... } }" (the current way to target the host without caring about what it is) will now instead target the host *and* all of its descendants. We're not worried about this breaking anyone now, but we should make the change fast before it gets more painful in the future. This also makes @host consistent with the @global rule we'll be adding to scoped style sheets in general (once I sit down and write the Scoped Styles spec), which shifts selectors in scoped stylesheets from being scope-contained to scope-filtered, just with the added twist of also shifting the context from shadow DOM back to light DOM. ~TJ
Received on Wednesday, 6 March 2013 23:04:10 UTC