RE: Proposal for adding @extend to CSS

± De : Tab Atkins Jr. [mailto:jackalmage@gmail.com]
± 
± Several years ago, the Sass preprocessor adding the @extend rule, which lets
± you declare that one selector "extends" another base selector, so that any
± rules that apply to elements matched by the base selector also apply to
± elements matched by the extending selector.
± 
± For example, you can "extend" a .error class with a .serious-error class, easily
± applying all the basic .error styling to your .serious-error elements as well.
± This lets you avoid duplicating anything - you don't need to put class="error
± serious-error" in your HTML, or ".error:hover, .serious-error:hover" in your
± CSS selectors, or manually copy over the .error styling into .serious-error
± ruels.
± 
± In August 2012, dbaron suggested something extremely similar
± <https://lists.w3.org/Archives/Public/www-style/2012Aug/0363.html>,
± based on a discussion with Yehuda Katz and Nicole Sullivan (Nicole provided
± the original inspiration for @extend in Sass).  I pointed out that this was just
± @extend with a different, slightly more awkward, syntax.
± 
± In January 2013, Philip Walton also proposed something extremely similar
± <https://lists.w3.org/Archives/Public/www-style/2013Jan/0241.html>,
± and I again pointed out that this was just @extend with a more awkward
± syntax.
± 
± I finally got together with Chris Eppstein, one of the primary maintainers of
± Sass, and banged out a spec for @extend as a CSS feature.  Natalie
± Weizenbaum, the creator and primary maintainer of Sass, has reviewed it
± and found it acceptable, so I now present it to the group for review:
± <http://tabatkins.github.io/specs/css-extend-rule/>
± 
± This proposal adds the @extend rule, based on the semantics defined by
± Sass.  It also adds the "placeholder selector", which is similar to a class
± selector, but no aspect of the DOM can cause an element to match it.
± Experience with Sass shows that this is extraordinarily useful in practice, as it
± lets you safely design styles without having to worry about accidentally
± clashing with an existing classname, and then just @extend elements into
± matching it.
± 
± To be precise, the semantics of @extend is that it causes elements to act as if
± they have whatever additional features are necessary to match the
± extending selector.  For example, in the following rule:
± 
± ```
± .serious-error {
±   @extend .error;
±   font-weight: bold;
± }
± ```
± 
± Any element matching .serious-error is treated as if it also has the .error class
± (as that's what's required in order to match the .error selector).  All selectors
± in the document that mention .error now potentially apply to .serious-error
± elements as well.
± 
± There are more examples in the document, so I won't reproduce them here.
± 
± The @extend rule has been one of the most popular and useful features in
± Sass since its introduction.  It can only be imperfectly implemented in Sass via
± selector rewriting (a naive implementation runs into combinatorial
± explosions; Sass uses heuristics to tell which selectors are "most likely" to be
± important and only exports those)..
± We can implement it perfectly in the browser by actually affecting matching,
± and bring this super-popular tool to millions of authors using plain CSS.
± 
± Thoughts?

Hi Tab,

I fully understands this first draft is only a "flex-basis" for discussion, but given it's what I have at hand, I'll comment on the document itself more than on the idea; I'll read the minutes of the next Houdini meetings for ideological matters ^_^

So. I had a look at the specification, but I remained hungry for more after reading it. I know it's not always the role of a specification to tell the "imperative story" of the things it defines, but in this particular case I wasn't satisfied with the "functional story".

As a starter, I would have loved to see a selector matching algorithm which is conforming this specification; I'm interested in particular in how we can implement this in a single-phase matching, if that's possible. My thoughts is that you can't perform this in a single matching phase and will first need to match rules containing @extend rules, modify the "matchable dom" and repeat until no more additional changes is made to the matchable dom. 

This means that selector matching now needs to be performed top-down as selector matching for an ancestor may affect what rules match one if its children as a result of the mutated matchable dom; this may harm the parallelization of matching. That being said, maybe some other characteristics of css matching already do so; that's why I would have liked to see this discussed. I also wonder what might be the performance impact (but I guess only a prototype might inform us).

My second thought is this simply isn't going to be easy to create a consistent matchable dom using @extend. I have some examples: 

    :not(.open) { @extend .open }
   .open { @extend :not(.open) }
   
   .a { @extend .b }
   .b { @extend :not(.a) }
   
   <div> <e1/> <e2/> </div>
   :not(button) + e2 { @extend button }
   :nth-last-child(2 of button, e1) { @extend button }

It may also be hard to manage security restrictions:

    a:visited { @extend button }

It's maybe possible to resolve those cases in a sensible way, but it may be harder than it looks at first sight when reading the spec.

Happy discussions in Sydney,
François

Received on Saturday, 31 January 2015 12:57:11 UTC