W3C home > Mailing lists > Public > www-style@w3.org > April 2012

Re: [css3-values] use cases and the design of 'cycle()'

From: Kang-Hao (Kenny) Lu <kennyluck@csail.mit.edu>
Date: Tue, 10 Apr 2012 04:14:04 +0800
Message-ID: <4F83430C.407@csail.mit.edu>
To: "Tab Atkins Jr." <jackalmage@gmail.com>
CC: WWW Style <www-style@w3.org>
(12/04/10 3:05), Tab Atkins Jr. wrote:
> On Mon, Apr 9, 2012 at 11:11 AM, Kang-Hao (Kenny) Lu
>> Use Case A: In a User Interface built by nesting elements (say,
>> <table>), set background color on the elements alternatively along the
>> nesting level. See picture[1]
>>
>>  table {
>>    background-color: cycle(gray, white);
>>  }
>>
>> doesn't work with the current definition of 'cycle()':
>>
>>  # The value returned by ‘cycle()’ must be determined by comparing
>>  # the inherited value I (the computed value on the parent, or, for
>>  # the root, the initial value) to the computed values Cn returned by
>>  # the n-th argument to ‘cycle()’. For the earliest Cn such that
>>  # Cn = I, the value returned by cycle is Cn+1. However, if this Cn is
>>  # the last value, or if there are no Cn that equal I, the computed
>>  # value of the first value is returned instead.
>>
>> because 'I' is always 'none'.
> 
> ?  Why is I always 'none' here?  Tables are allowed to have
> background-colors.  Also, 'none' isn't even a valid value for
> background-color.

Oops, I meant to say 'transparent'.

> Your example should work.  Of course, 'background-color' isn't
> inherited by default, so if you want it to pierce through <tr> and
> <td> to get to a nested <table>, you'll have to set "tr, td {
> background-color: inherit; }" as well.

I think this is too hacky a solution. It certainly doesn't quite do what
the script is doing right now: attaching class alternatively, and
sometimes you just don't know what is in between so you probably need
'table :not(table) { background-color: inherit; }'

Also, 'background-color' is a bit magical here, another example would be

  table {
    transform: cycle(rotate(10deg), rotate(-10deg));
  }

with

  table :not(table) {
    transform: inherit;
  }

which wouldn't work as expected. The general use case here is that
cycle() is used like :nth-child(an+b) but applies based on nesting level
instead of number of siblings.

>> Proposal B: 'cycle()' works as if there's an anonymous counter for each
>> declaration with a 'cycle()', which is incremented when entering
>> elements where that declaration applies and wins and decremented when
>> leaving such elements. 'cycle()' returns the value corresponding to the
>> value of the counter. (Some details about what 'a declaration' is
>> missing for the moment.)
> 
> Your proposal B requires us to either attach meaning to the *source*
> of a declaration (such that splitting "A,B{...}" into "A{...} B{...}"
> or merging in the opposite direction will change the behavior of the
> CSS by creating more/less counters) which has no precedent in CSS and
> is almost certainly a bad idea, 

Yeah, that's true.

> or requires us to compare cycle()
> declarations to see if they're identical (and thus should use the same
> counter) which also relies on value-equality, which you list as a
> problem.

Or you can compare by source string, but I think this is too hacky and
would create too many subtle bugs.

> It also works incorrectly if you have a chain of cycle()s that work
> together, but in the middle you instead set the value to an explicit
> option - the following cycle() will just ignore that value and
> continue to iterate to the entry following whatever the grandparent
> used.

I think I need an example to fully understand this. Can you give me an
example use case? Why would you want to have a chain of cycle()s? My
impression is that I don't think this behavior is actually desirable,
and this is only correct if you want the "use x if the parent is y..."
behavior, which as I said, is very different from "use x, and then y,
and then z..."

>> == Advantages ==
>>
>> 1. It is a lot more intuitive and less error-prone by specifying "use x,
>> and then y, and then z..." than "use x if the parent is y...". For
>> example, css3-lists has
>>
>>  # /* Default list style types for unordered lists up to 3 deep */
>>  # ul { list-style-type: disc; }
>>  # ul ul { list-style-type: square; }
>>  # ul ul ul { list-style-type: circle; }
>>  # /* Alternately, if Values & Units Level 3 is supported, replace
>>  #    the above three lines with: */
>>  # ul { list-style-type: cycle(disc, square, circle); }
>>
>> in the "Sample style sheet for HTML", which doesn't work without
>> Proposal B applied because the inherited value I is 'disc' from the
>> initial value (and people forget that) and so the 'list-style-type' of
>> the top level <ul> is 'square'.
> 
> Ah, yes, that's definitely an error.  This aspect is a bit of a
> footgun, but it should be quickly obvious in practice.  I'll fix the
> error.

I am quite interested in your fix. The best I can do is

  ul { list-style-type: disc; }
  ul ul { list-style-type: cycle(disc, square, circle);}

but it is no longer too useful if I can only reduce three declarations
to two. (I don't quite care about this use case though)

But anyway, I think this is far from obvious, and this is because "use
x, and then y, and then z...(repeat)" and "use x if the parent is y..."
require very different thinking. The current definition is mainly
designed for the latter as far as I can tell.



Cheers,
Kenny
Received on Monday, 9 April 2012 20:14:33 GMT

This archive was generated by hypermail 2.3.1 : Tuesday, 26 March 2013 17:20:52 GMT