[css3-background] Overly-clever background-position grammar

I and some other webdevs were talking about background-position
yesterday, and were struck by how confusing the grammar for it is.
For ease of reference, I reproduce it here:

<bg-position> = [
  [ top | bottom ]
|
  [ <percentage> | <length> | left | center | right ]
  [ <percentage> | <length> | top | center | bottom ]?
|
  [ center | [ left | right ] [ <percentage> | <length> ]? ] &&
  [ center | [ top | bottom ] [ <percentage> | <length> ]? ]
]

While the grammar is technically correct, it suggests several
incorrect interpretations due to its structure.  In particular, the
first line makes it appear as if you're not allowed to specify 'left',
'right', or 'center' by themselves.  The grammar does, in fact, allow
this (use the second clause and omit the second bit), but this is very
unclear.

As well, it's not clear that the two-keyword form can have the
keywords specified in any order, as the second clause requires the
horizontal component first.  You have to look at the the third clause
to figure this out.

Finally, while the official spec for our property grammar states that
concatenation binds tighter than |, we try not to rely on that,
because it's unclear.  The third clause relies on this, and if you're
not aware of the precedence rules, it looks like you can use an offset
from 'center'.

I suggest restating the grammar so that each class of forms is more
clearly encapsulated in each clause, even if it does admit multiple
ways to produce a given value.  That is, something like this:

<bg-position> = [
  [ <percentage> | <length> | left | center | right ] ||
  [ <percentage> | <length> | top | center | bottom ]
|
  [ center | [[ left | right ] [ <percentage> | <length> ]?] ] &&
  [ center | [[ top | bottom ] [ <percentage> | <length> ]?] ]
]

Here, I have collapsed the 1-value clause into the two-value clause by
using ||.  By switching to this operator rather than concatenation,
I've also made it cover the fact that you can put vertical keywords
before horizontal keywords.  In the 3/4-value clause, I've added an
additional set of brackets to make the binding explicit.

Alternatively, we could increase the verbosity somewhat, but make the
clauses more explicit:

<bg-position> = [
  [ <percentage> | <length> | left | center | right | top | bottom ]
|
  [ <percentage> | <length> | left | center | right ] &&
  [ <percentage> | <length> | top | center | bottom ]
|
  center &&
  [ left | right | top | bottom ] [ <percentage> | <length> ]
|
  [ [ left | right ] [ <percentage> | <length> ]? ] &&
  [ [ top | bottom ] [ <percentage> | <length> ]? ]
]

Here, the first clause is the 1-value case, the second is the 2-value
case, the third is the 3-value cases that include 'center', and the
fourth is the 3/4 value cases that don't include 'center' (and
restates some 2-value cases, but that's unavoidable without a lot of
extra effort).  The benefit of this is that the productions can then
be directly referred to, as they map well to the different ways you
must interpret the values.

~TJ

Received on Saturday, 28 May 2011 01:12:50 UTC