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

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).

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.

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%?

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

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.

-- 
Leif Arne Storset
Core Technology Developer, Opera Software
Oslo, Norway

Received on Friday, 19 August 2011 13:33:25 UTC