Suggestion for @global to help with <style scoped>

Summary
-------
HTML is defining <style scoped> in a way which best matches author
intuitions, but which is limited in some ways.  I propose @global as a
way to get around those limitations while maintaining the
intuitiveness benefits.  Hixie wrote an email explaining the relevant
reasoning and suggesting this proposal at
<http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2011-September/033222.html>.


Background
----------
HTML defines <style scoped>, which produces a stylesheet wherein the
rules are "scoped" to a subsection of the document.

There are at least two meanings for "scoped", though, both with
strengths and weaknesses:

1. A "scoped" selector is still resolved as normal against the
document, and the set of matched elements is then filtered at the end
to only include elements within the scope.

2. A "scoped" selector is resolved only against elements in the scope,
almost as if the scope was a separate document.

#1 is used in querySelector() when you supply a reference argument,
while #2 is used in queryScopedSelector().  Other selector engines
like Sizzle (used in jQuery) automatically use #2.  Evidence seems to
show that most authors intuitively expect #2, and are surprised by the
additional elements that can show up when using an API that does #1.
As such, HTML is planning to switch <style scoped> from #1 to #2.
(Thread discussing this starts at
<http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2011-June/032088.html>.)

One can patch #1 into working like #2 when required via the :scope
pseudo-class, as defined in
<http://dev.w3.org/2006/webapi/selectors-api2/#the-scope-pseudo-class>.
 In order to patch #2 into working like #1 when required, one needs a
different mechanism, which I propose as the @global at-rule.


Proposal
--------
We add an @global rule to Selectors 4.  The syntax of this is:

@global <selector> {
  <decl block>
}

In other words, it's exactly like a normal selector+decl-block, just
preceded by "@global ".  This switches the selector from matching in
the #2 sense to matching in the #1 sense.  The :scope pseudo-class may
still be used in the selector, and works the same way as it would in a
"normal" #1-style selector.

This is compatible with the Core Grammar.  To work properly, it will
require a change to the 2.1 grammar to allow at-rules inside of @media
blocks, but that change becomes more necessary by the day anyway.


Reasoning
---------
The #2 meaning of "scoped" appears to be more intuitive to authors,
and appears to be more commonly used.  The #1 meaning is useful, but a
minority of the time.  Thus, <style scoped> should default to the #2
meaning with an escape hatch to allow #1-style matching when
necessary.

Several other proposals to achieve this were made.  The strongest such
proposal was to keep scoped selectors in the #1-style, but make them
somewhat "magical", such that, if the :scope pseudoclass was not
present in the selector, it was automatically prepended to the
selector with a descendant combinator.  The effect of this is that,
for the most part, selectors *act* like a slight variant of #2. (Like
#2, they'll only match within the scope.  Unlike #2, they won't match
the scoping element itself.)  Only when :scope is explicitly put in
the selector do they act like #1.

This proposal was inadequate for a few reasons.  First, and most
importantly, it was pretty magical, which is something we try to
avoid; selectors are complex enough as they are without invisible
rewriting going on.  Second, the slight variation from "stock" #2
appears to be slightly less good.  Third, the requirement for an
explicit :scope makes it less good than a generic #1-style selector,
where the scoping element can occur at or between any element in the
selector.  (To achieve full feature parity is very verbose - the exact
equivalent to ".foo .bar" in the #1 style is ":scope .foo .bar,
.foo:scope .bar, .foo :scope .bar, .foo .bar:scope, .foo .bar :scope"
in this magical variant.)

There were other vaguely similar proposals, but none of them were as
acceptable as this.  The @global proposal, made by Hixie, is the best
suggestion so far for allowing <style scope> to default to #2 but
escape to #1 when required.

~TJ

Received on Monday, 19 September 2011 22:59:36 UTC