

Re: CSS Variables Draft Proposal

From: Boris Zbarsky <bzbarsky@MIT.EDU>
Date: Mon, 14 Feb 2011 16:28:14 -0500
Message-ID: <4D599E6E.8050002@mit.edu>
On 2/14/11 3:46 PM, Tab Atkins Jr. wrote:
> This term is underdefined for my usage,
> and perhaps not exactly what I want, though.


> You can't put a unit in and expect to use it as a unit, for example, the "@var $foo
> px;" is perfectly fine if used as a keyword.  This shouldn't be hard -
> the intent is just that you can't store a "partial value" in a
> variable and then compose it with something else to get a whole value
> (so you can't do something like "@var $foo px; p { width: 200$foo;
> }").
 > I heard conflicting statements about whether "token" was correct here,
 > so I just avoided the issue and used a different word.  What is the
 > correct term?

I think the problem you're having is that this concept of "value" is not 
really exactly how the CSS spec is defined at the moment, and different 
UAs have different internal concepts of "value".  At least as far as I 
can tell.

Offhand, I wouldn't be willing to claim that the same string is always 
treated as the same kind of "value" in Gecko, even.  It might well be 
context-dependent.  I'm not saying that's the case; just that nothing 
ensures that it's not.

I agree that a raw token stream may not be the right thing due to things 

   @var foo 255, 255);

which could add pretty oddly if $foo is used like so:

   color: rgb(0, $foo, 0);

(though in this case I think it'll just cause the whole property to be 
discarded).  But if we require that any close parens/curlies/brackets be 
matched by open parens/curlies/brackets in the variable definition, then 
it seems like a token stream with that restriction might be ok.  It 
would certainly make it much simpler to specify how variable 
substitution should work: you just tokenize the template, replace the 
$foo with the corresponding token stream, and then parse the resulting 
token stream.

If you want to do this in terms of values, then you have to define 
somewhere what the value sets for various properties are, which sounds 
like a pretty major undertaking.

> "component value" is defined in CSS2.1, at
> <http://www.w3.org/TR/CSS21/about.html#value-defs>.  It's not exactly
> what I want, but it appears to be closer in intent than "token".

Hmm.  So the problem is that nothing guarantees that different value 
types as defined here will be syntactically distinct (and in fact 
they're not).  Put another way, you can't tell what sort of value it is 
until you see how it's being used.  That seems unfortunate.

>> Currently in a situation like that (same property specified multiple times
>> in a declaration) only the last specified value needs to be kept by the UA.
>>   It sounds like your proposal is that this is no longer the case with
>> variables, right?
> Yes, though your gloss isn't completely correct, right?  If you make a
> declaration block contain the same property twice, and use the CSSOM
> to twiddle whether the second one's value is valid or not, you have to
> pay attention to the first one.

Gecko certainly doesn't.  Invalid stuff is dropped at _parse_ time and 
not exposed to the CSSOM at all.

In particular, up until now invalid stuff has always been dropped at 
parse time, since the whole point is that if you don't know what it is 
you can't parse it apart from just skipping over it.

> Do you just let this case fall down a
> slow path, where you effectively reparse the block?

No; this case simply doesn't arise right now.  You're introducing it, by 
requiring some sort of non-parse-time discarding behavior.

>>> Scoped stylesheets (those created with a `<style scoped>` element in
>>> HTML) have their own nested global scope.  Variables created or
>>> imported within a scoped stylesheet are only available within the
>>> scoped stylesheet; variables created in the outer global scope are
>>> still available in a scoped stylesheet.
>> I'm not sure I follow this.  Say I have this markup:
>>   <div>
>>     <p>
>>     </p>
>>   </div>
>> with stylesheets scoped to the<div>  and<p>.  If I have an @var in the
>> div-scoped sheet, can the p-scoped sheet use it?  Note that rules in the
>> div-scoped sheet apply to the<p>  and all, in general.
> No.  This is defined by HTML - I'm just restating the restrictions
> that<style scoped>  applies, for clarity.

What you're stating is different from what the HTML5 draft says about 
<style scoped> as far as I can tell.  Again, the div-scoped sheet's 
rules apply to the <p> if I read the <style scoped> draft correctly, but 
you're saying its @vars do not?

>> This needs to happen to understand how variables can actually be used; see
>> above;
> Does what Bjoern wrote help here?

Not terribly, no.  I'll try rereading it again to see if I can make 
sense of it this time...

> It'll be overrideable, so I doubt it'll cause any problems.

You mean replaceable?

It can still cause problems even so (esp. if multiple scripts interact, 
one of which writes it and one of which wants to mess with your new APIs).

> I'd also like there to be a window.css which forwards to
> window.document.css, for ease of use.

That seems to have even more scope for problems.

>>> To add a new map entry, we first define `css.stylesheet`, which
>>> implements the `StyleSheet` interface.  This stylesheet is treated as
>>> an author-level sheet placed after all other author-level sheets.
>>> Creating a new map entry creates a corresponding @var rule in this
>>> stylesheet.
>> What about adding other rules to the sheet?  Would they be applied to the
>> document?
> It acts like a stylesheet in the document, so yes.

So a question.... apart from the handling of !important, how is this 
different from the override sheet stuff CSSOM specifies already?

>>> Variables appear as themselves in specified values. If the variable is
>>> defined and valid, its computed value is the value of the variable. If not,
>>> its computed value is the variable name.
>> I don't understand this at all, if invalid values are supposed to be treated
>> like parse errors....  What is this trying to say?
> Invalid values are no longer parse errors, since some time before you
> quoted this out of the draft.

That doesn't answer my question.  Consider this style:

  div { color: red; color: $foo; }
  p { color: $foo; }

What is the specified value of "color" for <div>s?  What is the computed 
value of "color" for <p>s?  How do I reconcile those answers with the 
text quoted above?

>> 2)  Can the type be changed via the CSSOM?  I assume yes, to make Daniel
>> happy.  ;)
> Yeah.

A followup: what happens if you try to change to an unknown type?

>>   @var color $foo 12px;
>>   * { font-size: $foo; }
>> then do I get 12px font-size?  Or is the variable considered invalid if its
>> value in the @var can't be parsed as its type?
> The validity of the variable can be verified at parse time in this
> proposal, so the $foo declaration would be invalid, and no $foo
> variable would be created.  The font-size declaration is then invalid,
> as it references an undefined variable.

OK (though this is not clear from the spec).  Let's try a more 
interesting testcase:

   @var color $foo red;
   * { font-family $foo; }

If I have a font with a family name of "red" on my system, will I get it?

>>> The previous suggestion seems to put the typing in the wrong place.
>>> Typing doesn't help the CSS developer in any way, as CSS can figure
>>> out types as necessary all by itself.
>> Maybe... and maybe not.  It sort of depends on what variable values "are".
>>   See beginning of this mail.
> I mean that you can figure out types at the time of use.  You can't
> possibly infer types at definition time, as there is too much
> ambiguity.

OK, but my point is that sometimes you can't really figure out types at 
time of use either, without falling back on the actual tokens involved.

>>> This would only work if the OM interfaces were carefully designed in
>>> such a way that there is never ambiguity
>> Seems fragile....
> I agree.  We want to try this and see if it works, though, before
> throwing it out.

The problem is that by the time we decide it doesn't work the damage 
will have been done: we'll have interfaces we can't drop for compat 
reasons but that will sort of suck in actual use.  See getComputedStyle 
as it is currently practiced.

Received on Monday, 14 February 2011 21:29:17 GMT
