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

Re: CSS Variables Draft Proposal

From: Tab Atkins Jr. <jackalmage@gmail.com>
Date: Fri, 11 Feb 2011 13:19:30 -0800
Message-ID: <AANLkTik9KNXim6P9S0X6_tds-moeWdEg5AwUkB12rRuR@mail.gmail.com>
To: "Linss, Peter" <peter.linss@hp.com>
Cc: www-style list <www-style@w3.org>
On Thu, Feb 10, 2011 at 5:15 PM, Linss, Peter <peter.linss@hp.com> wrote:
[snip stuff about token streams]

The draft has a new section at the bottom dealing with possible
approaches for appropriately limiting the syntax, so we can prevent
confusing abuses while allowing useful stuff.

>>>>Using a variable that hasn't been declared is a syntax error.  (It's
>>>>valid to use a variable that hasn't been declared *yet* - the
>>>>declaration may appear later in the stylesheet, or in another sheet
>>> Don't use the term "syntax error" here. I read this as "invalid and may
>>> thrown away at parse time", which is clearly not your intent.
>>> Better to define referencing an undefined variable as having a 'null'
>>> value, or more likely a value of 'invalid' which is a special token
>>> meaning that it's there, but will always be invalid. You also need a way
>>> to "unset" a variable via script and/or set it to a null/invalid value.
>>You definitely understand my intent here.  I'm open to better ways to
>>express this.  I like the idea of an always-invalid special value.
>>I'll put that in the draft.
>>An interesting issue - how does an invalid variable get treated when
>>you ask to serialize the property?  I'm going to assume it's
>>serialized as itself, since the syntax for variable names is already
>>designed to always be invalid.  (Is this true?)
> You should serialize it with the variable in place, don¹t replace it with
> its value at serialization time (presuming you're serializing the CSSOM of
> the stylesheet, not the computed style). If you're serializing the
> computed style then an invalid variable wouldn't come in to play anyhow.

Oh, of course.  This is already specified in the draft - the specified
value of a property using a variable (what the CSSOM exposes through
StyleSheet) shows the variable itself.  Computed values are different,

>>> Invalid at parse time or at run time? If variables are changed via
>>> you should detect and deal with (or detect the absence of) loops after
>>> each change...
>>Runtime, I would think, since you can change the value of a variable
>>(and potentially introduce or remove loops) at runtime.
> Right, just needs to be clearly specified. (Still glad you took this on?
> :-)

Done.  I went with the "variables in cycles have always-invalid values".

>>>>Deleting a map entry either deletes the current declaration producing
>>>>that value, or deletes all declarations defining that variable.  The
>>>>former is more symmetric with the underlying behavior of the "change"
>>>>action, but the latter is more symmetric with the *apparent* behavior,
>>>>as the complexity of multiple declarations is hidden away.
>>> There should also be a way to access all declarations, even if
>>> Insert, remove, reorder, etc. Or (probably better) you can't change this
>>> list, only the values of the variables in it. And if you do, you're
>>> changing the @var object in whichever stylesheet it came from.
>>Yes, changing a var through the css.vars map is always just sugar for
>>changing the @var object in the underlying stylesheet.
> I _REALLY_ don't like that. There's another issue here, consider:

Huh?  Why?  It seems like the cleanest solution to me.

> @var $foo red;
> p { color: $foo; }
> div { height: $foo; }
> Is $foo valid or not? The right answer is, the @var declaration is valid,
> the first use is valid, the second isn't. Now I change the value of $foo
> to "10px"...

The variable is valid.  The 'height' declaration is not, while $foo is
'red'.  When $foo is changed to '10px', the color declaration is

> Now consider:
> @var $foo red;
> p { color: $foo; }
> ... Some random other style, maybe a different stylesheet...
> @var $foo 10px;
> div { height: $foo; }
> What's the color of the p? What's the height of the div? According to your
> current model, the value of $foo is "10px", so the first use suddenly
> stops working when a different stylesheet, perhaps linked from a different
> site get's applied. Authors are going to have a hell of a time tracking
> that bug down...

Yes, that's correct.  This is why we need a mechanism to protect
against global name collisions.  That can come later, though.

For now, though, inspectors can easily offer information about where a
variable value comes from, the same way they can tell you where a
particular value is coming from.

>>What's the use-case for messing with shadowed variable declarations?
>>You can access them through stylesheet groveling, if it's absolutely
> I'm not sure which one you're calling the "shadowed" one.

In code like this:

@var $foo red;
@var $foo blue;

...the first declaration is 'shadowed', in that it's not immediately
accessible through css.var.foo.  You have to look through stylesheets
to get at it.

> The authoring tool use case means having access to all the @var
> declarations in the stylesheet objects. You need to be able to change both
> the values and variable names, as well as insert and remove @var rules. If
> you make changes there to a "live" web site in a browser, you potentially
> have to re-evaluate all the style data. This can be expensive...

Who needs to re-evaluate?  The browser, the authoring tool, or
something else?  I'm not sure I understand who's having to do extra
work here.

> If you now tweak @var rules via document.css.vars.foo, what are you really
> changing? The one and only @var rule that happened to be the winner at the
> time? Which might be different the next time you change it?

Yes.  The @var rule that is currently in effect and providing a value.
 No other mapping of @var rules to .vars entries makes sense.

> As I think about it more, the document.css.vars list should be a separate
> map. It gets populated by the @var rules, but it a distinct entity. If you
> change the value in document.css.vars, you're only changing the "used"
> value in the map, not touching any stylesheet @var objects. You could add
> or remove to/from the css.vars map but you're only adding the values in
> the runtime "computed vars" map, not creating @var rules in any sheet. If
> you then make a change in the stylesheet objects, the affected @var rules
> get re-computed and re-mapped. (This will be an interesting algorithm, and
> needs to be spec'ed, if you change the value of an @var that's overridden,
> you don't touch the map, if you change a var name, add, remove or move a
> @var such that it now applies or no longer applies, you look at all the
> @var rules for that variable and recompute the map. Lather, rinse, and
> repeat when enabling or disabling stylesheets for all @var rules in the
> affected sheet. The alternative is you throw away the whole map and
> recompute any time something changes that affects it.)

That's possible too.  I figured that it was simpler/cleaner to simply
interact with the active @var rules directly, but we can use an
override map too.

I've marked it as an issue.

> My concern wasn't the case sensitivity, it was:
> @var $main-color red;
> @var $maincolor blue;
> Those should be distinct variables. You change does address that.

Well, those would have been different under my previous text, too.
The first would have been accessed as vars.mainColor, the second as

But yeah, now the first is vars['main-color'], the second is vars.maincolor.

>>> And if the value of the variable is a list of values? (like for a
>>> shorthand)
>>I don't understand the context of the question.
> Consider:
> @var $foo 10px 20px;
> And then in my script:
> var foo = document.css.vars.foo;
> What is 'foo'?

Ah, I see.  The immediately preceding question was about mapping CSS
var names to keys in the var map, so the "And if..." made me think it
was some continuation on that theme, which was confusing.

The returned value is an object implementing the CSSVariable interface
(not defined yet), representing its value, which .toString()s to "10px
20px", and exposes some bag of other appropriate interfaces (which is
possibly none in this case, I dunno).

Received on Friday, 11 February 2011 21:20:26 UTC

This archive was generated by hypermail 2.4.0 : Friday, 25 March 2022 10:07:56 UTC