Fwd: [css3-images] Order of color-stop fixup

On Fri, Aug 19, 2011 at 5:51 AM, Leif Arne Storset <lstorset@opera.com> wrote:
> Tab Atkins Jr. <jackalmage@gmail.com> skreiv Thu, 18 Aug 2011 03:46:12
> +0200
>> The first problem is illustrated at
>> <http://www.xanthir.com/etc/gradient-fixup-order.html>.  The page
>> explains the problem, but I'll summarize it here:
>>
>> In the example, we animate the width of the box from 200px to 1000px,
>> at the same time as we animate the background from linear-gradient(to
>> right, red 50%, white 100px, blue 100%) to linear-gradient(to right,
>> red 10%, white 100px, blue 100%).  (In other words, we only change the
>> position of the red stop.)
>>
>> Because the white stop is specified as 100px in both gradients, one
>> would expect that at all points during the transition the white stop
>> is either at exactly 100px (when the red stop resolves to less than
>> 100px) or is at the same position as the red stop (when the red stop
>> resolve to greater than 100px).
>>
>> However, if you do position-fixup early, as the first gradient on the
>> page does, you get a weird effect where the white stop jumps *ahead*
>> of the red stop due to the way the linear interpolation works (the
>> effect is maximized halfway through the transition, when the red stop
>> is at 180px and the white is at 200px).
>>
>> Doing the position-fixup at the last moment instead keeps the white at
>> a reasonable position the whole time - it's always Math.max(100px,
>> red.position).
>
> Sorry if I'm being dense, but this doesn't make sense to me. I don't get
> why the white stop should at any point be greater than MAX(red stop, 100px).
> Where
> do you get this from? If I pass the plain gradient, simulating the
> transitioning effect now moved to level 4, it gives the expected result in
> Chromium, Firefox and Opera (see attachment).
>
> If I attempt a plain CSS transition in Chromium (also attached), it gives an
> effect reminiscent of what you've shown, but only because 'red 10%' (which
> applies immediately due to transitioning gradients not yet being supported)
> is _less than_ 100px for part of the transition (as opposed to 'white 100px'
> being more than 100px, which is what I'm getting from you).

Yes, doing a transition currently, where the gradient immediately
jumps to the end state, doesn't illustrate anything useful about this.
 The problem arises when you blend gradients.


> Stepping through the code in your script, I see that it's not positioning
> the white stop based on the actual position of the red stop:
>
> (at 50%:)
> width       = 600px (50% between 200px and 1000px)
> red 50%     = 180px (50% between 50% * 600px = 300px and 10% * 600px =
> 60px)
> white 100px = 200px (50% between MAX(50% * 600px, 100px) and MAX(10% *
> 600px, 100px), which works out to 50% between 300px and 100px)
>
> It seems that the misplaced white stop comes from interpolating 'red'
> between 60px and 300px and interpolating 'white' between 100px and 300px
> (seen from the 50% mark). But the rules don't care about red's
> hypothetical starting placement at 60px when placing white; they only care
> about red's actual current placement at 180px, which is greater than white's
> 100px.

Incorrect.  The rules, as written, care completely about red's
hypothetical position at the two end points, *because* the rules
currently specify early fix-up.  You *must* first resolve the starting
gradient into absolute lengths (which pushes the white stop out to
300px, when you take into account the box's width at the 50% point),
and do the same for the ending gradient (white stop isn't pushed, so
it's at 100px).  *Then*, after doing so, you're allowed to blend them.


> Anyway, this strikes me as a strange way of going about it. With the red
> stop's
> position being specified both at the start and the end, why don't you just
> transition from 50% to 10%?

Because the rules don't allow it.  You're arguing that we should do
blending before we do fixup, which is exactly what I'm arguing for as
well.  That gives us the behavior of the second gradient in the
example.  You'll notice that your added gradient has identical
behavior to the second one on the page.


> In any case, there are no implicitly positioned stops here, so swapping 2
> and 3 should not make a difference.

It does, because you *do* need to resolve implicit stops before you
blend (otherwise, you won't know how to blend).  So, if you push fixup
to after blending, implicit positioning must swap places and occur
before it.  (Alternately, we could mandate two blending rounds, so the
order would be (1) implicitly position first and last stops, (2) blend
what you can, (3) fixup, (4) implicitly position the other stops, (5)
blend the rest.)


> Having said all this, our implementation experience doesn't rule out
> swapping them, but as an implementor of CSS gradients, keeping the order
> (2,3) is preferred, as the code appears to be simpler and more efficient.
> Furthermore, as a web developer and user of CSS gradients, keeping the order
> (2,3) is strongly desired, for the reasons Brian Manthos has explained quite
> thoroughly.

I'm neutral on the aesthetics - I think both methods have unique
useful visual effects.

~TJ

Received on Friday, 19 August 2011 16:52:08 UTC