June 30, 2011 18

Morf.js – Custom Easing Functions for CSS3 Transition


Morf Screenshot

I love CSS3 transitions! They’re easy to implement, more performant than the setTimeout based alternative & because of this work really well on mobile devices1.

One area CSS transitions are not as flexible as the Javascript alternatives is easing functions. Libraries such as jQuery & Scripty2 have a suite of really compelling functions that just aren’t available with CSS transitions.

So we’re left to choose from:

  • linear
  • ease
  • ease-out
  • ease-in
  • cubic-bezier

cubic-bezier does provide us with a lot of flexibility but it still has its limitations. What if we want to implement a bounce effect? Unfortunately we’re out of luck as this is not something that can be modelled with a cubic-bezier.

Thomas Fuch’s raised this very issue earlier this year and pointed to how Apple uses CSS animations instead of transitions for more complex effects. He suggested vendors add the ability to enable a Javascript callback to provide custom easing functions but it looks like this isn’t a viable solution.

Introducing Morf, a Javascript work-around for hardware accelerated CSS3 transitions with custom easing functions.

How do I use it?

Using it is simple but does require that you trigger the transition from Javascript. To transition an element to a new state you would do the following:

// Get a reference to the element
var elem = document.getElementById('elem');

var trans = Morf.transition(elem, {
        // New CSS state
        '-webkit-transform': 'translate3d(300px, 0, 0) rotate(90deg)',
        'background-color': '#FF0000'
    }, {
        duration: '1500ms',
        timingFunction: 'bounce'

Thats it! Your element will then transition right 300px, rotate 90deg & change colour to red using the bounce easing function.

For more information on the available easing functions checkout the Morf demo or view the docs available on GitHub.


Morf requires the following:

  • A WebKit browser capable of CSS Animations (Morf uses @keyframes animations under the hood)
  • Shifty.js (>= 0.1.3) – Morf can be downloaded with or without Shifty pre-bundled

Why is this WebKit only?

Although other browser vendors have started to add CSS Animations (e.g. Firefox 5) they do not yet have an alternative implementation for the WebKitCSSMatrix object which is used to calculate the interpolated matrix values.

How does it work?

So you know how to use it but you want to know how it works? Well, what Morf actually does is create a CSS3 animation on the fly for the requested transition. In other words at the time that Morf.transition is called, all the necessary keyframes are generated to give the impression that a transition has taken place.

Even though this is actually a CSS Animation, Morf does its best to masquerade as a transition, event throwing a webkitTransitionEnd event when its finished.

You may also just want to use Morf as a CSS animation generator, in which case you can get the generated keyframes in CSS format using the .css property. So, continuing the above example:


Tweening CSS

To work out all the interpolated CSS states, Morf uses the fantastic Shifty.js along with some custom code to handle matrix transformations. Shifty is responsible for working out all regular CSS tween values. e.g. width, height, background-color.

Tweening Matrix Transformations

In order to tween the 3D matrix, I had to add some custom functions to the WebKitCSSMatrix object. The process of accurately tweening between two matrix states requires that the matrixes themselves be first decomposed into their composite parts (translate, rotate, scale etc). Once these composite parts are known, its a matter of tweening between each part of each state and then rebuilding the composite matrix.

The bulk of this calculation is done using the custom WebKitCSSMatrix.decompose() function. This function is a Javascript implementation of pseudo code provided by the W3C. Its likely that this is pretty close to how WebKit produces tween values internally but in Javascript rather than native code, so not quite as quick.

In order to get the decompose() function working I also had to supplement the WebKitCSSMatrix object with some other helpful matrix functions and add a basic Vector4 implementation.

Note: The decompose() function is fairly expensive so its only called once for the start and end state of each transition.

My WebKitCSSMatrix additions are standalone and don’t require Morf.js. It may be useful to others so feel free to repurpose them for your own projects: WebKitCSSMatrix.ext.js (MIT License).

  1. Ok, not all mobile devices! A lot of Android phones lack hardware acceleration so don’t perform too well []
  • Pingback: Morf.js – Flexible Beschleunigungsfunktionen für CSS3 Transitions » t3n News

  • http://www.facebook.com/matoilic Mato Ilic

    I’ve recently started planning a library like this as part of a bigger project. Looks like the project is going to take less time to realize. Thank you for the awesome work.

  • http://www.joelambert.co.uk Joe Lambert

    Glad it will be useful, would love to know if you use it as part of something larger!

  • http://www.facebook.com/profile.php?id=1614214071 Stefan Schult

    Hi, will you support the Firefox 5?

  • http://www.joelambert.co.uk Joe Lambert

    Hi Stefan, I’d love to support Firefox but until they implement MozCSSMatrix this isn’t possible I’m afraid.

  • http://twitter.com/brokenseal Davide Callegari

    Nice!! Please change the link to gihub on your page http://www.joelambert.co.uk/morf cause it’s wrong

  • http://www.joelambert.co.uk Joe Lambert

    Thanks for the heads up, link is changed and now points to the correct GitHub repo.

  • Pingback: CSS3 Transitions with custom easing functions - Programming Blog

  • Pingback: Revision 30: IE10, Google+ und Dr.Web | Working Draft

  • http://twitter.com/CSSchops CSS Chops

    Thanks Joe. Really excellent work. Brings to mind Robert Penner’s flash work : http://robertpenner.com/easing/easing_demo.html

  • Pingback: CSS Chops » CSS3 Transitions with custom easing functions

  • http://www.joelambert.co.uk Joe Lambert

    Morf.js does actually use the Penner functions under the hood :)

  • http://www.facebook.com/liquidcolors Simon Sanladerer

    Using an rotation-transition on an img with “position:fixed; z-index: 1″ will make the element overlap another div-container with “position: relative; z-index: 2″ for a few ticks. This could be a browser bug (Chromium), but when I’m using a default webkit-transition this isn’t happening.

    Are you manipulating the z-index anywhere with your script at runtime?

  • http://www.joelambert.co.uk Joe Lambert

    Hi Simon,

    Thanks for getting in contact, could you open an issue at https://github.com/joelambert/morf/issues and include a link to an example of the behaviour you describe (jsfiddle or jsbin would be good). I can then take a look and see if it’s a morf bug or a browser issue. Thanks

  • http://www.facebook.com/liquidcolors Simon Sanladerer

    Ok I’ll do that but I’m currently busy with various other things and will get back at it in a few days. 

  • http://www.facebook.com/liquidcolors Simon Sanladerer

    Seems like this was a Chrome-Bug which hasn’t happended since I switched to Boilerplate v2.

    Will keep you updated if anything else comes up.

  • http://www.joelambert.co.uk Joe Lambert

    Great, thanks for letting me know.

  • Pingback: 31 Fresh HTML5/CSS3 Tips and Techniques for designer & Developers | Multy Shades