Re: [css3-values] bare parenthesis as calculation/grouping construct (was: Disposition of Comments, remaining issues, and moving to CR)

(I am changing the subject and Cc- w3c-css-wg, sorry about discussing
this with an irrelevant subject line for a while.)

(12/07/06 15:42), Tab Atkins Jr. wrote:
>>>>>  * they'd prevent the working group from using parentheses in any
>>>>>    other contexts in CSS property syntax (though the first point is
>>>>>    also an argument against most other possible uses)
>>>> My bet is that this is not likely to happen. It's not like CSS is a
>>>> fast-changing language so worrying too much about "reserving for the
>>>> future" doesn't make much sense to me, and if you want grouping
>>>> constructs in the future, we still have [] and <>.
>>> One must always worry about being future-friendly, or else you'll make
>>> mistakes that are really annoying later.  (You'll probably make them
>>> anyway, but hopefully less often if you're watching out for them.)
>> I agree, but I'd be curious what we might want to use parentheses for.
>> And, is it not possible to overload the meaning of parentheses just like
>> how it is overloaded in other programming languages (e.g. in JS bare
>> parenthesis is used after a control flow keyword and it is also used to
>> mean a function call)?
>> It seems that we have extensive experience about this in other languages
>> so we can just learn from them.
> The main thing I expect to use parens for in the future is their
> primary purpose - grouping things.  For example, currently, if we want
> a function to take a general selector as an argument, we have to make
> it the last argument and have no optional args, because the comma in
> selectors clashes with commas between arguments.  Requiring people to
> wrap the selector in parens if they use commas in it would help.

I've been wondering why you think about the bare parenthesis syntax as
"you can do math in here". To me, it's as you said, just a general
grouping construct. It's the '+', '-', '*' or '/' that does the math.
The parenthesis, as with any other programming language, is just there
to make values parseable.

Now I start to see some potential issues.


  '+' is overloaded to mean both "plus" and "next-sibling combinator".
'/' is overloaded to mean both "divide" and "general value separator".

But I need an example to illustrate that this is a real issue (see below).

> Variables have a very similar problem in the default values of the
> var() and parent-var() functions.  If I ever convince the group to do
> Mixins, we'll have the same problem there.  Parens could be useful in
> both of these circumstances for grouping values into a single
> argument.

Calculation is about grouping values into a single value too. So, to see
if there are real problems I think it would be better to examine
specific examples to see if there are real conflicts.

Example 1a:

  border-radius: 1em (2em / 3em) 4em

This is admittedly somewhat confusing, but I'd say it's fine to say it's

Example 1b:

  font: (14px / 2)

Similarly, this is equivalent to "font: 7px", not "font: 14px / 2"

Example 2a:

  var(foo, (bar1, bar2))

There's no '+', '-', '/' or '*' here so you don't need to do calc()
syntax checking here, and I also don't think the "bare parenthesis as
calculation idea" asks you to do calc() syntax checking any time you see
a bare parenthesis pair, or otherwise it just doesn't work with the
Media Query syntax.

Example 2b:

  var(foo, (bar1 + bar2, bar3))

So, even if there's a "+" here, as far as I can tell, the proposed
behavior of the default value var() syntax with the bare parenthesis
extension is to feed the token stream "bar + bar2, bar 3" to downstream.
It's up to the the downstream to do any checking with the token stream.

That is,

  width: (var(invalid-foo, (bar1 + bar2, bar3)))


  width: (bar1 + bar2, bar3)

. Now, the property value top level requires a calc() syntax checking
for a bare parenthesis pair and it's invalid.

Example 2c:

  width: (var(invalid-foo, (1em + 2em))

This would work, just like

  width: (1em + 2em)

Example 2d:

  width: var(invalid-foo, (100% - 2em))

With the above definition, this is invalid because "width: 100% - 2em"
is. So indeed this might confuse people if the "bare parenthesis as
calculation" idea is accepted and we remove calc(). Some options:

1. Introduce arg() for an argument with ",". That is, give up the bare
parenthesis extension to var().
2. Keep calc() so it can be used for this purpose.
3. Ask people to do ((100% - 2em)) in this case.
4. Adopt XSL-FO-like behavior where "width: 100% - 2em" just works. I
haven't studied how it works with 1a and 1b above, though.

Likewise, attr()/toggle(). These are both var()-like functional
notations anyway.

The "bare parenthesis as calculation" proposal only asks bare
parenthesis to mean calculations when it's at the top level of a
property value, the behavior of it in the rest of the locations, is,
admittedly, underspecified, and it needs to be investigated. So here it

Example 3:

  linear-gradient((10deg + 10deg), red (10% + 2em))

I don't think we'll introduce "fold multiple arguments into one" syntax
in all functional notations in css3-images, so it's safe to introduce
calc() syntax checking at the top level within

There are some corner case calc()-accepting locations like
nth-child()/@keyframe and I think it's safe to ignore those at the
moment. (It's considered OutOfScope by css3-values too, I think).

That's go into the future:

Example 4:

  element((auto + min-content))

I don't think there's any way you would expect calculation to happen
within element() since it doesn't take a property value, so there should
not be calc() syntax checking at the top level within element(), and
what this does is to select a <min-content> element preceded by an
<auto> element.

If people really think this is confusing we can introduce selector(), as

  element(selector(auto + min-content))


  * calc()/()
  * ()/selector()

, I would go with latter, but both these tags are, as far as I can tell,
not necessary.

If I am asked to compare

  * calc()/()
  * ()/arg() (described above)

, I think I would go with the latter too.

Any more examples we can analyze?


Received on Friday, 6 July 2012 11:36:42 UTC