Hello I'm Jellybo

Bounce.js - a great tool for creating complex CSS3 animations

Bounce.js is a tool that helps you generate complex CSS animations. It enhances the easing function possibilities with interesting bounce effects which can be used in combination with standard functions (tasks, operations) such as translate, rotate, scale or skew. Bounce.js also provides you with a fun editor at http://bouncejs.com , where you can find many examples and choose from default animations.

Bounce.js generates CSS keyframes for your animation by combining your chosen transformations and easing functions. It uses metrix3d . E.g.:

                
@keyframes animation { 
  0% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  4.7% { -webkit-transform: matrix3d(1.45, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.45, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  9.41% { -webkit-transform: matrix3d(1.883, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.883, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  14.11% { -webkit-transform: matrix3d(2.141, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(2.141, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  18.72% { -webkit-transform: matrix3d(2.212, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(2.212, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  24.32% { -webkit-transform: matrix3d(2.151, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(2.151, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  29.93% { -webkit-transform: matrix3d(2.048, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(2.048, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  35.54% { -webkit-transform: matrix3d(1.979, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.979, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  41.04% { -webkit-transform: matrix3d(1.961, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.961, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  52.15% { -webkit-transform: matrix3d(1.991, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.991, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  63.26% { -webkit-transform: matrix3d(2.007, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(2.007, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  85.49% { -webkit-transform: matrix3d(1.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
  100% { -webkit-transform: matrix3d(2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } 
}
                
                

Hover animations

The main downside to these animations is that you can only use the generated keyframes with an animation parameter. This creates a problem when it comes to hover animations. To solve this issue, you can use the following JS helper function, which adds a class upon hovering over with a cursor over the element and adds another class when the cursor leaves the element. Everything has been optimalised so that it looks as smooth as possible.

            
function HoverClassHelper($parentElem, _hoverInClass, _hoverOutClass, _duration) {
    var _animationStage = 0;
    var _animationRunning = 0;
    var _inAnimation = 0;
    var _nextCommands = [];
    var _useTimer = !!_duration;
    function addInClass(next) {
        $parentElem.classList.remove(_hoverOutClass);
        $parentElem.classList.add(_hoverInClass);
        var animEndFn = function () {
            next();
        };
        if (_useTimer) {
            setTimeout(animEndFn, _duration);
        } else {
            _nextCommands.push(animEndFn);
        }
    }
    function addOutClass(next) {
        $parentElem.classList.remove(_hoverInClass);
        $parentElem.classList.add(_hoverOutClass);
        var animEndFn = function () {
            next();
        };
        if (_useTimer) {
            setTimeout(animEndFn, _duration);
        } else {
            _nextCommands.push(animEndFn);
        }
    }
    function start() {
        _animationRunning = 1;
        _animationStage = 1;
        addInClass(function () {
            _animationStage = 2;
            _animationRunning = 0;
            if (_inAnimation === 0) {
                end();
            }
        });
    }
    function end() {
        _animationRunning = 1;
        _animationStage = 3;
        addOutClass(function () {
            _animationStage = 0;
            _animationRunning = 0;
            if (_inAnimation === 1) {
                mouseEnter();
            }
        });
    }
    function mouseEnter() {
        if (_animationRunning === 0) {
            _animationRunning = 1;
            _inAnimation = 1;
            start();
        } else {
            _inAnimation = 1;
        }
    }
    function mouseLeave() {
        _inAnimation = 0;
        if (_animationRunning === 0) {
            _animationRunning = 1;
            if (_animationStage === 2) {
                end();
            } else {
                start();
            }
        }
    }
    function animationEnd() {
        if (_nextCommands.length > 0) {
            var fn = _nextCommands.shift();
            fn();
        }
    }
    function eventsOn() {
        $parentElem.addEventListener("mouseenter", mouseEnter, false);
        $parentElem.addEventListener("mouseleave", mouseLeave, false);
        if (!_useTimer) {
            $parentElem.addEventListener("animationend", animationEnd, false);
        }
    }
    function eventsOff() {
        $parentElem.removeEventListener("mouseenter", mouseEnter, false);
        $parentElem.removeEventListener("mouseleave", mouseLeave, false);
        if (!_useTimer) {
            $parentElem.removeEventListener("animationend", animationEnd, false);
        }
    }
    function enter(){
        mouseEnter();
    }
    function leave(){
        mouseLeave();
    }
    eventsOn();
    return {
        eventsOn: eventsOn,
        eventsOff: eventsOff,
        enter:enter,
        leave:leave
    };
}
            
                

Application

HoverClassHelper($parentElem, _hoverInClass, _hoverOutClass, _duration)

  • $parentElem - lement, to which the events of mouseenter and mouseleave get attached. Its classes will be changing.
  • _hoverInClass - class which gets set up after hovering over the element with mouse and runs the initial animation
  • _hoverOutClass - class which gets set up after leaving the element and runs the final animation
  • _duration - duration of the animation. If it is not specified, the parameter is taken from animationend in $parentElem event
The value returned is an object with the eventsOn and eventsOff functions thanks to which the entire plugin gets initialized or deinitialized. The initial animation can be directly started and consecutively terminated by initializing the final animation thanks to the enter and leave functions.

An example

Simple example

CSS

                    
            .hoverIn {
                animation: animationHoverIn 1000ms linear both;
            }
            .hoverOut {
                animation: animationHoverOut 1000ms linear both;
            }
                    
                

JS

                    
            HoverClassHelper(document.getElementById("hoverExample"),"hoverIn","hoverOut");
                    
                

Sometimes you need your animation to always play in its entirety even by a quick hover of the cursor over the element. For example, the last 300ms do not need to animate themselves, if the final animation starts right afterwards. You can do that by setting the _duration parameter to be shorter than the duration of the entire animation.

JS

                    
            HoverClassHelper(document.getElementById("hoverExample2"),"hoverIn","hoverOut",700);
                    
                

Bounce.js a Jellybo

Jellybo uses bounce.js transformations in his products as well. Check out his Menu Icon 005: