[css3-transitions] Interpolating between values from different information sources

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