W3C home > Mailing lists > Public > www-style@w3.org > February 2011

Re: CSS Variables

From: Tab Atkins Jr. <jackalmage@gmail.com>
Date: Mon, 7 Feb 2011 10:31:35 -0800
Message-ID: <AANLkTinnihsrtU2in2h6VoxD0jxV2nN91GmSanOV0Kdx@mail.gmail.com>
To: Daniel Glazman <daniel.glazman@disruptive-innovations.com>
Cc: www-style list <www-style@w3.org>
On Sun, Feb 6, 2011 at 3:32 AM, Daniel Glazman
<daniel.glazman@disruptive-innovations.com> wrote:
> Le 06/02/11 01:34, Tab Atkins Jr. a écrit :
>
>> 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).
>
> Hyatt and glazou, to be more precise.

Ah, right.


>> 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.
>
> Please detail how variables are affected by media declarations. What
> are the values here for color and background-color on a screen ?
>
>  @var $foo red;
>  @media screen {
>    @var $foo yellow;
>    color: $foo;
>  }
>  @media screen, print {
>    @var $foo blue;
>    background-color: $foo;
>  }

Unless there's something crazy that we're overlooking, vars should
respect media declarations.  Thus, in your above example, both color
and background-color are blue, as that's the last valid variable
active.

I recognize that the example given is relatively confusing, but it's
the sane behavior.


>> 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.
>
[snip]
> But please understand it adds a cycle to style engines if a variable
> is used but not defined yet in a stylesheet... The style engine will
> need to cycle if the variable assignments happen AFTER the variables
> are used.

Indeed.  It's a somewhat unfortunate implication of having sane and
declarative variable behavior.


>> The syntax isn't complex.  What we're going with so far is this:
>>
>> @var $foo red;
>
> I don't understand that $ at all and I think it is useless. Just make
> the first parameter following @var an ident and that's enough. Using
> $var to ACCESS a variable is fine, modulo the impact on parsing.

The $ isn't obviously a modifier like var() is.  If it's required for
accessing the var, it should be required for setting the var as well,
to reduce author confusion.  Basically, it should look the same
everywhere.


> I admit
> I haven't thought at it yet. Thinking out loud, I think the var()
> notation is better because more conformant to CSS's common practice.
> It will also be easier to implement.

I don't *think* either choice is particularly easier or harder to
implement.  I preferred var() as well, but I got pretty overwhelming
feedback from both implementors and authors that they preferred the
brevity of just using a $ prefix.


> I don't think the preprocessing-on-server-side argument is a good one.
> The purpose of a Variables spec is to obsolete such preprocessing
> anyway.

Indeed.


>> 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".
>
> That's where it becomes tricky. So you're suggesting a new global
> object called "css". It's then "window.css"... I think "document.css"
> is more reasonable, for many reasons. Anyway.
>
> You will have to detail how document.css.vars is populated. Example:
> I set a variable through |document.css.vars.foo = "blue"| and THEN
> add a document a link element loading a stylesheet itself defining
> the foo variable. I suppose your answer will be "no problem, the
> stylesheet will override the dynamic assignment". Ok, but it has
> to be specified.

Indeed, this edge case needs to be addressed.  I thought of it
earlier, but hadn't decided on what to do yet.

(I'm kinda leaning toward a "virtual stylesheet" hanging off of the
css object that implements the StyleSheet interface.  Setting a brand
new var would be a shortcut for creating an @var rule in the virtual
stylesheet.  Then we just need to define the level and ordering of the
virtual stylesheet - I guess it would be an author sheet, but I don't
know whether it should come before or after all the real sheets.)


> You will also have to clearly detail the security considerations.
> What happens if I set a variable in my stylesheet to a string containing
> eval() of some JS, for instance (just thinking out loud).

I'm not sure I understand the case you're worrying about.  Could you
give an example?  Are you talking about something like this?

css.vars.foo = "eval('alert(document.cookie)')";

If so, that's equivalent to declaring "@var $foo
eval('alert(document.cookie)');" in your CSS.  In other words, it's
just an invalid value (as eval() isn't a recognized CSS function).


> The assigned value of a variable has probably to be a term (Cf. CSS
> grammar) or a white-space separated list of terms.

Yes, indeed.  Our thoughts right now are that, while specifying the
type is optional, the value must still be something valid for a *some*
type.  The valid types are just (a) every property, (b) every
primitive value, and (c) a few other useful values that aren't
primitive, like <position> (rather than having to specify a type of
<background-position>, which is only valid to use on
'background-position') or <border-side> (rather than <border-left>,
which can only be used on 'border-left', not 'border-top').

This area is under active investigation right now, but your statement
is correct in general.


>> This example supposes that there is a global css object defined on
>> document (also on window, forwarding to document.css) that gives
>
> Not sure this forward is needed or even reasonable.

I don't want to require a "document." in front of every access when
it's not needed.  This is a useful convenience feature.  We (meaning
my group within Chrome team) are concerned with code verbosity, and
want to reduce it wherever doing so is possible and wouldn't hurt
readability.


>> 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.
>
> The model in our (Hyatt and myself) proposal is **absolutely** needed
> for authoring tools. If variables can be accessed but not authored,
> you'll create massive issues for web authoring tools. We **must** have
> a way to create/edit @var rules in the CSS OM of a given stylesheet.
> I will not accept a proposal that's not meeting this requirement, sorry.

Oh, I completely agree.  Don't worry, what you guys have defined is
just fine for what it does.  It's just bad for author use.  Sorry if I
implied that we wanted to drop all the direct stylesheet manipulation
stuff.


>> 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
>
> Hmmm... No need to bloat the global namespace here. Isn't
>
>  document.css.vars.foo = new document.css.Values.Color("red");
>
> better? You can even used that to translate "red" into rgb() or #
> notations if the string is needed.

I don't think it's better.  ^_^  There's 25 too many characters there.

Though, doing:

css.vars.foo = new css.Color("red");

is another reasonable approach.  I don't think there's a huge
difference between a prefixed item sitting in the global scope and a
non-prefixed sitting underneath a grouping item.


> Let me conclude : your proposal is made of two things. First a new
> proposal for Variables. I find it incomplete since it does not address
> authoring tools' requirements.

Luckily, not actually a problem, as I clarified above.


> Second, a massive change of the CSS OM
> (and I welcome that since the current one is a mess) that requires a
> lengthy spec. Not a problem, but we need something well architectured
> here. I'm fine with your "document.css" but we probably need to write
> down the requirements before designing anything. I am willing to help
> here.

Sounds good.  Let's start that discussion elsethread.  Note that we're
not yet working on the CSSOM changes.  We're working on just the CSS
part of the experimental implementation first.

~TJ
Received on Monday, 7 February 2011 18:32:28 GMT

This archive was generated by hypermail 2.3.1 : Tuesday, 26 March 2013 17:20:37 GMT