While reviewing CSS3 V&U, I realized that 'cycle()' doesn't really solve
a use case I thought it would solve.
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'.
I would guess that my use case is more common than
Use Case B (example 16): make an element italic, but make it normal if
it's inside something that's italic.
though I can't quite prove it. Perhaps Use Case A is really not very
common. In any case, I believe they are both certainly more common than
Use Case C (example 17): cycle between markers for nested lists
because I doubt anyone would really use <ul> more than three levels, but
I am happy to be proved wrong with links to examples.
So, is my use case important to change the current definition of
'cycle()'? If yes, I have two proposals:
Proposal A: For non-inheritable properties, define the inherited value I
as the nearest non-initial computed value of an ancestor element. Make
no change to the inherited value I for inheritable properties.
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.)
I prefer Proposal B, and here some advantages and disadvantages:
== 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'.
2. Duplicate values in a 'cycle()' work as expected, which is more
natural, I believe.
3. The issue about using 'cycle()' with other values I raised earlier[2]
no longer applies.
4. It no longer relies on value equality which doesn't seem to be
well-defined for many multi-value properties (i.e. Is "x y" = "y x" for
'counter-increment'? What about "auto" and "auto auto" for
'background-size'?)
5. It can be later easily extended to rely on an explicit counter, which
can be a lot more powerful. (This is not certainly a good idea so I'll
not post examples for the moment.)
== Disadvantages ==
1. Use Case B (toggling italic/normal) no longer works. This is
essentially because "use x, and then y, and then z..." and "use x if the
parent is y..." are quite different.
(Perhaps we should have a specialized function for this kind of use
cases, say, 'toggle()')
2. Is this proposal actually implementable?
I think we need more use cases to see what we really want.
[1] http://www.w3.org/DesignIssues/diagrams/tabulator/Picture07.png
[2] http://lists.w3.org/Archives/Public/www-style/2012Apr/0206
Cheers,
Kenny