- From: Tab Atkins Jr. <jackalmage@gmail.com>
- Date: Sat, 5 Feb 2011 16:34:44 -0800
- To: www-style list <www-style@w3.org>
A few weeks ago I gave a talk about some experimental things some of our teams at Chrome are working on. (You can see the subsequent blogpost at <http://www.xanthir.com/blog/b49w0>.) I obviously want to bring all of them to the group soon, but I want to start on Variables, being the simplest and most-requested feature. We've been arguing about CSS Variables for a long time, but could never agree on how it was supposed to work. This sucks for authors, particularly as the rise of preprocessing frameworks like SASS have shown just how popular and useful variables are in designing and theming webpages and webapps, both large and small. I and some other Chrome engineers have put together a proposal for variables that is very similar in nature to what glazou proposed in <http://disruptive-innovations.com/zoo/cssvariables/> (the syntax is a bit different, but that's mostly a bikeshedding detail). Here are a few 1. Variables are mutable. You can have multiple declarations of the same variable in a stylesheet, and the last one wins, per normal CSS tradition. You can change variables using the CSSOM, and the updated value will flow through all the uses of the var. This is very necessary to solve, for example, the use-case of having several similar elements scattered across a page all change their backgrounds together. Mutable variables let you just set up a variable for the shared color, use it in their declaration, and then tweak the variable value in javascript. This is enormously easier than either grovelling through stylesheets and somehow finding the correct rule to alter, or iterating through all the elements and adjusting their inline style. 2. Variables are document-global. Once defined, they can be used in any stylesheet on the page, preceding or following, @import'd or just linked in separately. Last time variables were discussed, this was a significant sticking point. The major objection was conflicts between different usages; for example, a page-specific style defining a variable that happened to conflict with a variable defined by the site template's style. To help solve this, proposals of varying complexity were introduced to limit the scope of variables and allow them to 'bleed out' (or in) in controlled ways. We think that this solution is best addressed at a higher level. Using the global namespace is definitely easier for authors, and conflicts in this space will simply get worse as we introduce more subspaces (variables, mixins, specialized ones like font-faces and counter-styles). This should be addressed by a general mechanism - we're going to be experimenting with a Module system to help out here (outlined in my blog post), so we'll see how it goes. 3. Variables respond in the obvious way to dynamic changes. Adding a var (whether through the CSSOM variable map, adding a new @var rule directly to a stylesheet via the CSSOM, or adding a new stylesheet to the document) enables use of that var everywhere. If a var is used before it's defined, adding a definition later will make all uses suddenly work. Removing vars with any method will either fall back to a previous definition for that name, if one exists, or just make all usage of that variable invalid. The syntax isn't complex. What we're going with so far is this: @var $foo red; bar { color: $foo; } The @var rule declares a single variable, taking a name and then arbitrary CSS as a value. The var name must start with a $ character, so we can use $ as an unambiguous indicator in the content that a variable is being used. CSSOM access is done through the global vars map, like so: console.log(css.vars.foo); // logs "red", given the above css.vars.foo = "blue"; // Everywhere $foo is used is now "blue". This example supposes that there is a global css object defined on document (also on window, forwarding to document.css) that gives access to document-global CSS things, like vars. This way you don't need to know which stylesheet a var comes from to alter it, making variables even easier to use. One could imagine that this map is instead defined on stylesheets, but that's more difficult to work with for literally no gain. (Technical detail: if there are multiple @var rules declaring the same variable, the var map entry points to the current "active" rule.) (Another technical detail: scoped stylesheets should scope their vars, and preferably other global namespaces. A mechanism needs to be provided to grab the css environment that a particular element sees, rather than the global css environment, so one can manipulate variables defined in scoped stylesheets easily.) I believe this model of interaction is enormously simpler than what was in glazou's proposal, which would require a script to grovel through all the rules in all stylesheets to find var rules, and use verbosely-named functions to alter them. This model is also easily extensible for when we get the CSSOM improvements that allow type-based manipulation of values. To enable the CSSColor interface on a var, for example, declare it like so: @var color $foo red; Or set it in script like so: css.vars.foo = new CSSColor("red"); // strawman syntax, don't pay any attention So, thoughts? I'm willing to write this spec, if the WG accepts it as a work item. We're already working on an experimental implementation regardless, so we can see how it works in practice for people. Discuss! ~TJ
Received on Sunday, 6 February 2011 00:35:33 UTC