Easy easing gets easier; hard easing stays hard

I’ve just been reading about CSS Transitions, which are part of the CSS3 draft specification, and which has been experimentally implemented in Opera, Webkit (Safari, Chrome and Konqueror amonst others) and in nightly builds of Firefox (with documentation on the ever useful devmo). CSS transitions provide a declarative way to animate CSS properties – in other words an easy way for a web page developer to say “this menu item should smoothly change from red to green, and get 3 pixels taller when the user puts their mouse over it”. As such they will be a great step forward in helping to make the web a prettier, more friendly place. Unfortunately it’s missing some of the most useful easing functions.

An easing function is essentially a curve which defines how the speed of the animation changes over time. Consider an element moving 100 pixels in 100 seconds. With a linear easing function, after 10 seconds the element will have moved 10 pixels, after 73 seconds it will have moved 73 pixels – it’s a simple 1:1 relationship between time and the value being animated (position, in this case):

In the CSS transitions spec, the easing function is always considered as starting from (0,0) and ending on (1.0,1.0), so the graph sticks to these figures. In practice you can think of the graph as showing time running from 0 to 100% of the transition period on the x-axis, and the relative value of the transition running from 0 to 100% on the y-axis. By changing the shape of the easing curve it’s possible to create animations which seem to accelerate or decelerate, which often gives a more pleasing result. In adddition to “Linear” the spec defines the following easing functions: ease, ease-in, ease-out, ease-in-out:

In addition to these basic easing functions, you can specify a custom function. In practice what you’re actually defining is the location of the two bezier control points that affect the easing function, but it does mean that you can go some way outside of the default curves if you really want to:

But here’s where the restriction comes in. Your custom function actually only specifies the location of two bezier control points – and they have to be within the range 0.0 to 1.0. You can’t have an easing function with extra intermediate points in it, and you can’t have an easing function whose value goes above 100% or below 0%. What that means, in practice, is that you can’t have an animation that appears to overshoot its destination before sliding back into place:

It also means that you can’t have an animation that overshoots its destination value, then undershoots, then overshoots, eventually rippling to a halt:

And you can’t create a bouncing ball animation:

You know that rebounding effect that you get when you scroll too far on an iPhone menu? You can’t re-create that. Perhaps you’d like to code your e-commerce site with a bounce effect as people drop things into their shopping baskets. Nope, you can’t do that either.

Yes, technically it’s possible to string several animations together by writing some script to catch the “transitioned” event and then trigger another animation. The devmo page even gives an example of doing exactly that to continuously animate a box with text in. But really that’s a crap workaround when the real solution is for the spec to allow more sophisticated easing curves.

It’s great that web developers will soon be able to trivially animate CSS values using simple easing functions. It’s not so great that they can’t trivially use more complex easing functions. We live in a world where mobile phones have user interfaces which pulse, bounce and ripple, providing visually stimulating feedback. Is it too much to ask for our browsers to easily allow the same?