Re: CSS Variables Draft Proposal

On Fri, Feb 11, 2011 at 7:41 PM, Boris Zbarsky <bzbarsky@mit.edu> wrote:
> On 2/9/11 8:22 PM, Tab Atkins Jr. wrote:
>>
>> The syntax is `@var`, followed by whitespace, followed by the variable
>> name (which must start with a $, and then follow the IDENT
>> production), followed by whitespace, followed by an arbitrary series
>> of CSS tokens, capped by a semicolon at the end.
>
> The draft on your page now says "component values", which is actually worse,
> since the concept of "component value" is undefined.
>
> In any case, the question of what possible values of a variable are is
> something we really need to pin down before most of the rest of the
> discussion makes sense, because it affects where and how variables can be
> used and hence which use cases they address.
>
> I _think_ you have some personal mental model here, but I don't understand
> what it is, nor how much it's tied to a particular implementation.  So can
> we make it a priority to get this part straightened out?  I suspect that
> once we do a lot of the other discussion around variables might need to be
> revisited.

Component value isn't undefined, it's a term referring to a single
'thing' in a property definition (as opposed to a property value,
which is the whole value).  This term is underdefined for my usage,
and perhaps not exactly what I want, though.

I'm not sure what term I *do* want, though.  The mental model is that
the stuff you put into a variable have to be "values".  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?


>> Using variables is very easy too - they can be used anywhere you could
>> use a component value:
>
> What's a "component value"?   That's not a concept that's present in the CSS
> specs, nor in Gecko's implementation.  Is it something from Webkit's
> implementation?  Something from that mental model of yours?  As I said
> above, the exact definition here affects where variables can actually be
> used.

"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".


>> 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
>> entirely.)
>
> What is the expected behavior of this markup:
>
> div {
>  color: red;
>  color: $foo;
>  color: $bar;
> }
>
> in a browser that supports variables if $foo and $bar are both not defined?
>  If $foo then suddenly becomes defined?  If $bar then becomes defined?

This is defined in the draft now.  An undefined variable computes to
an always-invalid value.  CSS then proceeds as normal.  So, in this
case, the color is red at first (as both of the latter two rules
contain invalid values and so are ignored).  When $foo becomes
defined, assuming it's defined to a valid color value, then the color
becomes $foo's value.  Same when $bar is defined.


> 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.  Do you just let this case fall down a
slow path, where you effectively reparse the block?


>> Variables exist in the global scope.  @import'ing a stylesheet makes
>> any variables contained within it available to all other sheets.
>> Similarly, linking in a stylesheet makes any variables contained
>> within it available to all other sheets.
>
> There probably need to be some caveats here about sheets that are not
> applied for various reasons (disabled, not applied due to media queries,
> whatever).  Given that browsers can just not load sheets for media they
> don't support, in theory, the only thing that makes sense to me is that if a
> sheet is not applied then neither are any of its @var rules.

These caveats are already in the draft.  They act like you expect.


>> 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.


>> Variables declared in an @media block are only available if the media
>> declaration is true.
>
> Assuming that's even allowed; does the core grammar allow nested @-rules
> now?

It has to, given @page and the margin @-rules.  If we haven't yet
changed it to accommodate this, then we're somewhat behind.


>> Multiple Variable Declarations
>>
>> If the same variable name is declared in multiple @var rules, the last
>> valid declaration wins.  For this purpose, UA-defined variables come
>> before all author-defined rules, which come before all user-defined
>> rules.  Within each category, the ordering is document order.  (This
>> is intentionally identical to normal CSS precedence rules
>
> Except it's not; it has user and author in the opposite order.  Within the
> set of author sheets the order does match, I agree.
>
>> Changes to CSS Grammar
>> ----------------------
>>
>> To be completed with boring details.
>
> This needs to happen to understand how variables can actually be used; see
> above;

Does what Bjoern wrote help here?  It *sounds* like he's got the basic
grammar down, but I'm not confident enough to say definitely whether
or not it's right.


>> For use by normal authors, I'll be proposing a new global object on
>> `document` named `css`.
>
> Do we have any data on how web-compatible this is?  Also, you just mean a
> property on Document objects, right?  Not a global object in the ES sense or
> anything?  I'm not sure what "global" is supposed to mean there.

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

Each document has a css object on it.  Currently this only contains
the vars map (and maybe the virtual stylesheet used for script-defined
vars), but it may be used to host other CSS things later, like
constructors for the various types of values.

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


> What about scoped style sheets?  I guess those can walk the sheet
> directly...

No, I want to expose a similar object that reflects the scoped
environment, but don't have any particularly good ideas on how to do
so yet.


>> Changing the value of a map entry changes the underlying value in the
>> stylesheet for the declaration being used to produce that value.
>
> What if the setter is called with a string that can't be parsed as a
> variable value (whatever that might mean)?

Hm, not sure.  I guess we should fail the declaration, and probably
throw an exception.  I'll put a note in the draft about it.


>> 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.


>> (Should this exist in `document.stylesheets`?
>
> If it's going to apply to the document, then yes.

Ok.


>> Serializing Variables
>
>> 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.


>> (The definition of a 'type' is intentionally somewhat loose right now.
>>  At minimum, every primitive value is a type, as is every property.
>> We may also want some complex component types, like<position>.)
>
> Fwiw, on your webpage you forgot to escape the <> there.

Whoops, thanks.  Fixed.


> I'm not sure what "primitive" value means here.  Do you mean the kinds of
> values defined by http://www.w3.org/TR/css3-values/#values or something
> else?

The stuff defined in V&U, yeah, or defined similarly in other specs
(like the new subtypes of <image> defined in Image Values).


>> ### Optional Typing ###
>>
>> Optional typing is just an amendment to the declaration syntax that
>> allows the author to specify the variable's type directly.  It would
>> look like this:
>>
>> ~~~~
>> @var color $foo red;
>> ~~~~
>
> Some obvious questions:
>
> 1)  What should a UA do with an unknown type?  Is the @var rule still
> created, for example?  More on this below.

That *would* be a syntax error.


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

Yeah.


> 3)  If I have this CSS:
>
>  @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.


>> ### Late Typing ###
>>
>> 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.


>> 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.

~TJ

Received on Monday, 14 February 2011 20:50:11 UTC