- From: Tab Atkins Jr. <jackalmage@gmail.com>
- Date: Wed, 1 Jun 2011 19:12:21 -0700
- To: www-style list <www-style@w3.org>
We've got an internal effort to try and make webapps and large webpages easier to write and maintain. As part of this we want to develop Variables and Mixins, but another idea we had was that of Hierarchy, or Selector Nesting. The idea here is to enable selectors to be nested within each other, so that instead of writing: foo { prop: val; prop: val; } foo bar { prop: val; } you can write: foo { prop: val; prop: val; & bar { prop: val; } } The advantage of Hierarchies is that you can keep related styles in the same place, rather than spread across your document, and you can hence more clearly see how various style rules relate to each other. This helps reduce cognitive load on the reader and improves maintainability by taking advantage of CSS's {} scoping. SASS provides an example of this idea in action <http://sass-lang.com/tutorial.html#nesting>. Hierarchies and Mixins work really well together to enable reusable, hierarchical chunks of CSS to be defined then included in the appropriate place. Using this approach to define styled widgets avoids many of the issues that traditionally have to be solved via the specificity rules. (See footnote for an example) We've considered a few different syntax options, but have settled on recommending the use of a single '&' character to indicate hierarchical scope. This allows both space-separated and directly adjacent nesting to be supported: foo { prop: val; & bar { prop: val; } &:hover { prop: val; } } One issue that we've not yet completely resolved is the interaction between Hierarchies and selector lists. For example: foo, bar { & far { prop: val; } } Currently we are leaning towards this being supported and equivalent to: foo far { prop: val; } bar far { prop: val; } On the other hand, we are leaning towards only allowing selector lists in nested selectors via repeated insertion of the '&' character: foo { & bar, & far, &:hover { prop: val; } } With respect to the CSSOM, nested selectors would be exposed as .cssRules on the CSSStyleRule object, identical to how CSSMediaRule works already. This feature, as we currently have it imagined, is incompatible with the current Core Syntax. However, it degrades well in existing browsers if you put the nested rules below all the properties in a rule. There is another, slightly more verbose, syntax option using @-rules that would only require the same changes that Mixins do, where we allow @-rules inside of rules. FOOTNOTE: Mixins and Hierarchies -------------------------------- Using Mixins and Hierarchies together, set of nested behaviours can be defined hierarchically, then included where necessary using @mixin. Keeping the behaviours defined within a mixin reduces pollution of the CSS namespace and hence reduces the need to resort to specificity rules. However, the use of a @mixin allows these rules to be used in the appropriate places: @trait hover-behaviour { foo { prop: val; prop: val; & bar { prop: val; &:hover { prop: val; prop: val; } &:active { prop: val; prop: val; } } } } far { @mixin hover-behaviour; } FOOTNOTE: Extended Example -------------------------- Hierarchy looks like unnecessary line-noise when you see only small examples. It really shines when you see it in larger examples, like you'd get in actual applications. Here's an example from a recent internal presentation. This is an actual chunk of CSS taken from the code for a slideshow we recently wrote: .slide.image { background-repeat: no-repeat; background-size: cover; background-position: top left; } .slide.image .credit { /*...*/ } .slide.image .counter { /*...*/ } .slide.image section { /*...*/ } .slide.image section h1, .slide.image section h2 { /*...*/ } .slide.image section.bottomLeft { /*...*/ } .slide.image section.bottomRight { /*...*/ } .slide.image section.topLeft { /*...*/ } .slide.image section.topRight { /*...*/ } .slide.image section.topWide { /*...*/ } .slide.image section.bottomWide { /*...*/ } The duplication is clear and somewhat jarring. Here's the same thing, rewritten to use Hierarchy: .slide.image { background-repeat: no-repeat; background-size: cover; background-position: top left; & .credit { /*...*/ } & .counter { /*...*/ } & section { /*...*/ & h1, & h2 { /*...*/ } &.bottomLeft { /*...*/ } &.bottomRight { /*...*/ } &.topLeft { /*...*/ } &.topRight { /*...*/ } &.topWide { /*...*/ } &.bottomWide { /*...*/ } } } ~TJ
Received on Thursday, 2 June 2011 02:13:08 UTC