- From: Ian Hickson <ian@hixie.ch>
- Date: Thu, 15 Sep 2011 00:55:19 +0000 (UTC)
The question posed in this thread is whether selectors in scoped style sheet blocks should be affected by ancestors of the scoped block. For example, should this be possible: <body class="archive"> ... <section> <style scoped> section > h1 { border-bottom: solid; } body.homepage h1 { color: red; } body.archive h1 { color: gray; } </style> <h1>Hello</h1> <!-- this changes colour based on whether it's on a page with <body class=homepage> or <body class=archive> --> <p>Welcome.</p> </section> ... </body> Several people suggested that this would be confusing, because of situations such as the following: <aside> <h1>Snippets from other blogs</h1> <section> <!-- content inserted from another blog --> <style scoped> section > h1 { border-bottom: solid; } p { text-align: left; } aside p { text-align: right; } </style> <p>Hello.</p> <aside> <p> I'm happy. </p> </aside> </section> </aside> Here, the embedded content expects to just style its own aside, but ends up styling all of its contents because it happens to be inside another aside. This, it is argued, is undesireable. On Thu, 16 Jun 2011, Lachlan Hunt wrote: > > This is the purpose of the :scope pseudo-class that is defined to match > the contextual reference elemnt, which for scoped stylesheets, will be > the parent of the style element. [...] > > http://dev.w3.org/2006/webapi/selectors-api2/#the-scope-pseudo-class Thus, to do the first example, we would use these rules: section:scope > h1, :scope section > h1 { border-bottom: solid; } body.homepage :scope h1 { color: red; } body.archive :scope h1 { color: gray; } ...and for the second example, we would use: section:scope > h1, :scope section > h1 { border-bottom: solid; } :scope p { text-align: left; } :scope aside p { text-align: right; } Unfortunately, as some people implied on the thread, this is rather awkward and certainly not intuitive. Thus the first proposal: to force all selectors in a scoped style block to not have any component simple selector matching any element that is an ancestor of the scoping element. Unfortunately, this breaks the first example above. Thus, the second proposal: On Thu, 16 Jun 2011, Dimitri Glazkov wrote: > > What if we do this: > > 1) By default, <style scoped> implies that all selectors in this > stylesheet are prefixed with ":scope". > 2) Unless the ":scope" is already in the selector. I think it might be better to phrase it as follows: A sequence of simple selectors in a selector chain can only match the scoped element and its descendants unless a sequence of simple selectors later in the selector chain contains the :scope pseudo-class. This avoids having to define any parsing mangling, but gets more or less the same effect (actually it gets a better effect, since it means that a selector chain consisting of just a simple selector can match both the scoping element and its descendants). Thus, to do the first example, we would now use these rules which are a bit of a compromise between the intuitive (but wrong) original case and the more explicit case: section > h1 { border-bottom: solid; } body.homepage :scope h1 { color: red; } body.archive :scope h1 { color: gray; } ...and for the second example, we would just use the intuitive case: section > h1 { border-bottom: solid; } p { text-align: left; } aside p { text-align: right; } However, as easy as that appears at first blush, I fear it would be seem quite magical to authors who have trouble enough understanding CSS as it is. Consider: <aside> <section> <style scoped> aside section h1 { ... } /* matches nothing */ aside section:scope h1 { ... } /* matches h1 below */ </style> <h1>Example</h1> ... </section> </aside> Never before in CSS has making a selector more specific actually increased the number of elements it can match. On Thu, 16 Jun 2011, Boris Zbarsky wrote: > > Especially if we allowed the CSSOM in this situation to include the > implied ":scope" on selectors that did not include it in the text (in > which case, this is a simple parse-time transformation on the > stylesheet). I think if we made the CSSOM reflect different selectors than what was in the style sheet, that would be very confusing for authors, especially if we rewrote the rules to match as described above (so some selector chains in the input would become two selector chains in the CSSOM). On Thu, 16 Jun 2011, Tab Atkins Jr. wrote: > > I think it's pretty easy to learn that bare selectors only apply to > children of the scoping element, not the scoping element itself. With the rule as described above, there is no distinction between the element itself and its descendants. The boundary is between the scoping element and its parent, not at the element itself. On Fri, 17 Jun 2011, Kornel Lesi?~Dski wrote: > > That feels magical and a bit backwards to me. > > Why not scope all selectors except ones starting with :root? > > .foo {scoped} > > :root .foo {matches outside scope} That seems just as magical. :-) With the proposal above, you would have: .foo { ... } /* scoped */ :root .foo:scope, :root :scope .foo { ... } /* matches outside scope */ Admittedly in the case where .foo might match either the scoping element or descendants of the scoping element, the full syntax is a bit longer. For comparison, here's what the above examples would look like with your proposal. For the first: section > h1 { border-bottom: solid; } :root body.homepage h1 { color: red; } :root body.archive h1 { color: gray; } ...and for the second (same as with :scope's magic): section > h1 { border-bottom: solid; } p { text-align: left; } aside p { text-align: right; } Personally I think having the magic relating directly to :scope is more understandable -- :scope is all about scoping. But only barely. With :root doing the magic, you're really using :root as an @-rule; you might as well at that point actually do so: <style scoped> section > h1 { border-bottom: solid; } @global body.homepage h1 { color: red; } @global body.archive h1 { color: gray; } </style> This does have the advantage of meaning there's no magic. Where do implementors stand on this? Are @rules an acceptable solution? (If so, we'd want to pass it by the CSSWG first.) There was some discussion about whether to include the scoping element in the scope: On Tue, 19 Jul 2011, Tab Atkins Jr. wrote: > > I think it's best for that case to *not* match. Otherwise, you have to > explicitly remember to add a :not(:scope) to every rule that might match > the scoping element. > > It's very easy to style the scoping element by using :scope explicitly. I think that would be confusing for the same reason we don't exclude the root element in regular selector matching. On Wed, 20 Jul 2011, Kornel Lesi?~Dski wrote: > > I think it should match the scoping element, as I expect this pattern to be > common until <style scoped> is widely supported: > > <div id=widget> > <style scoped> > #widget foo {} > </style> > </div> True. On Wed, 20 Jul 2011, Ashley Sheridan wrote: > > While I agree that that might be a common pattern, I disagree that it's > actually a good one. Consider an ad service which wraps everything in a > custom <div> tag. If the scope allowed the immediate parent to be > included as part of the scope, then it could allow the advert to be > altered in a way that could negatively affect the users of the site the > ad appeared on. That's possible anyway -- the advertisment could just not use scoped="", or use a hostile <script>. -- Ian Hickson U+1047E )\._.,--....,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Received on Wednesday, 14 September 2011 17:55:19 UTC