- From: Tab Atkins Jr. <jackalmage@gmail.com>
- Date: Fri, 10 Sep 2010 10:45:38 -0700
- To: www-style list <www-style@w3.org>
Sorry, this'll be a bit long. While biking home yesterday I was thinking about the linear-gradient() interpolation problem. I realized that the issue with interpolating between angle and no-angle linear gradients was equally a problem with circle and ellipse radial gradients, so I resolved to keep that in mind when trying to solve the former. Further thought, though, led me to realize that the problem ran even deeper than that; as the problem is currently defined, two no-angle gradients can run into it in some situations! In general, the problem is with the two endpoints of the transition calculating themselves with different information sources. I can illustrate it plainly. Let's start with a simple example that doesn't cause any problems: (I'll be using the two-point syntax which I plan to add as soon as we come up with a resolution to the interpolation problem.) div { position: absolute; left: 0; right: 200px; background: linear-gradient(left 0px, left 200px, red, blue); transition: right 1s, background 1s; } div:hover { right: 400px; background: linear-gradient(left 0px, left 400px, red, blue); } In this code, when you hover the div, it widens, and the background gradient does too. Nothing too special; it's simple to see how the gradient is interpolated by transitioning just the end-point. Now, a problematic example: div { /* same as above */ } div:hover { right: 400px; background: linear-gradient(left 0px, right 0px, red, blue); } Without a transition, this situation is identical to the previous one. With a transition, though, there's ambiguity. How do you transition from "left 200px" to "right 0px", particularly when the right edge is moving? At what point do you stop looking at the left edge and start looking at the right edge? A possible solution is to say that references to "right" and "bottom" in a <bg-position> are syntax sugar for a calc() expression on a "left" or "top" value, and then interpolate the calc(). In other words, rather than interpolating between "left 200px" and "right 0px", you're interpolating between "left calc(0% + 200px)" and "left calc(100% - 0px)", which you can just interpolate component-wise. This will produce a different transition than the first example, but it will be well-defined. This feels like just a problem-specific bandage over the general issue, though. radial-gradients not only have interpolation problems between circle/ellipse, but between all of the <size> values as well. I'm not really willing to "solve" the problem by eliminating these, though, because I *strongly* feel they're really useful (webkit radial gradients are basically useless to me since they only allow a double-point/radius form). There are other places in current CSS where values that we want to interpolate between depend on different information sources, and thus suffer from the same problem. For example, interpolating between height:0 and height:auto, which is necessary for implementing a smooth-scrolling <details> element. My thoughts right now are that we should do something intelligent when we can (like in the left/right case for <bg-position>), but when we can't, just cast both values into an equivalent interpolable representation, updating this representation as necessary if the information sources change. This "update as necessary" step isn't any more difficult in general than what has to be done anyway to handle percentages or relative lengths that may be changing at the same time. (This means, though, that I'll need to slightly redesign radial gradients so that they have the option of being specified in an explicit syntax, so that we *can* cast different ones into an equivalent interpolable syntax.) Thoughts? ~TJ
Received on Friday, 10 September 2010 17:46:25 UTC