My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Thursday, March 12, 2015

taming CSS animations via restyle

I am working on a little gamish project that requires quite a lot of CSS animations ... I ended up updating restyle in order to simplify as much as possible this task: here what's new!

A not-so-fool CSS animations approach

First of all, we all know how tedious and boring is to write manually a cross platform CSS animation.
So here just one good thing about restyle, it gives us the ability to define all the burden at once:
// restyle object with 2 described animations
var gfx = restyle({
  '@keyframes text-highlight': {
    '0%':   { color: 'inherit' },
    '100%': { color: '#FFF' }
  },
  '.highlight': {
    animation: {
      name: 'text-highlight',
      duration: '500ms',
      iterationCount: '1',
      direction: 'normal'
    }
  },
  '@keyframes grow': {
    '0%':   { transform: 'scale(1)' },
    '100%': { transform: 'scale(2)' }
  },
  '.grow': {
    animation: {
      name: 'grow',
      duration: '1s',
      iterationCount: '2',
      direction: 'alternate'
    }
  }
});

// set the animation class to the element
myElement.classList.add('highlight');

// we can now do something once done 
gfx.animate(
  // the node that is animating
  myElement,
  // the animation **name** (not the class)
  'text-highlight',
  // the callback
  function (e) {
    // drop this class
    e.currentTarget.classList.remove('highlight');
  }
);

Timer based fallback included

Since restyle is compatible with browsers that do not even support animations or animation fallbacks, but since each object is aware of its own used CSS, whenever a browser without animation events is used the method will find out the animation duration automatically.
We can test the functionality through another method, .getAnimationDuration(el, animationName)
myElement.classList.add('highlight');
gfx.getAnimationDuration(myElement, 'text-highlight'); // 500


myElement.className = 'grow';
gfx.getAnimationDuration(myElement, 'grow'); // 1000

Caveats

In order to be able to understand which animation is used, and being animations named via key frames but actually assigned through classes (where only one animation per time happens), the fallback parser has to understand which class contains the animation and with which duration.
This is actually quite complex black magic but the good part is that it happens behind the scene, however the duration method works only for animations already assigned so it's not a good idea to pre-assign durations since these depends on the class that will trigger such animation.
The delay has no fallback (yet) so, if needed and known upfront, we could attach the callback later on.
Last, but not least, the returned object has a .drop() ability so that is always possible to revoke a callback previously assigned to trigger at animation end.
myElement.classList.add('highlight');
var after = gfx.animate(myElement, 'highlight', function(){
  console.log('will never happen');
});

// before the animation ends
after.drop();
How to cancel animations? Well, that's provided automatically via CSS, we can simply drop or change className and we are done.
Hope this new helper will be useful, at least it has been playing nice with my little game.
Cheers

No comments: