Beyond Keyframes

Modern web animation techniques

So, who is this guy?

¯\(º_o)/¯

Hi, I'm Eli

@elifitch

I work here.

And I do a lot of front end development, animation, and...whatever this is.

I'll be shreiking about

How to betterify your CSS animations

How the browser makes all your pretty pixels

When JS animation makes sense

How to write more performant JS animations

How JS animation libraries can help

CSS is great for small state changes

Performance is
fucking
important

CSS properties are not created equal.

Browser rendering steps

Layout

Paint

Composite

Mind your layout

Paint is slow

Lets cheat.

Test baby test

Paint areas

Layer borders

Scroll bottlenecks

FPS

Property Breakdown

Layout


width/height

top/right/bottom/left

padding

font-size

Paint


color

background

box-shadow

border-radius

Composite


opacity

scale

rotate

translate

Why not use CSS to animate everything?

It can be a little limiting.

When you get crazy, so does your workflow

JS gives you the power.

Independent transforms

Complex easing (physics!)

Animating weird stuff

Animating along a bezier curve

Randomized animation

IE8/9 support! hahaha hah haa... .......

Moving on.

Wait, isn't JS animation slow?

Myth Busting Time.

JS !== janky

jQuery $.animate is the devil.

setInterval vs. requestAnimationFrame

RAF isn't scary

							
var opacity = 0;

// runs every 16ms to try to achieve 60fps (1000ms/60 ~= 16ms).
var fadeIn = setInterval(function() {
	if(opacity < 1) {
		element.style.opacity = (opacity += 0.05);
	} else {
		clearInterval(fadeIn)
	}
}, 16);
							
						
							
// requestAnimationFrame: Attempts to run at 60fps based on
// whether the browser is in an optimal state.
var opacity = 0;

var fadeIn = function() {
       if(opacity < 1){
         window.requestAnimationFrame(fadeIn);
         element.style.opacity = (opacity += 0.05);
       }
}

fadeIn();
							
						

Performance is more than properties

Don't thrash

							
var h1 = element1.clientHeight;           // Read (measures the element)
element1.style.height = (h1 * 2) + 'px';  // Write (invalidates current layout)

var h2 = element2.clientHeight;           // Read (measure again, so must trigger layout)
element2.style.height = (h1 * 2) + 'px';  // Write (invalidates current layout)

var h3 = element3.clientHeight;           // Read (measure again, so must trigger layout)
element3.style.height = (h3 * 2) + 'px';  // Write (invalidates current layout)
							
						
							
// Readenzie
var h1 = element1.clientHeight; 
var h2 = element2.clientHeight; 
var h3 = element3.clientHeight; 

// Writenzie
element1.style.height = (h1 * 2) + 'px';
element2.style.height = (h1 * 2) + 'px';
element3.style.height = (h3 * 2) + 'px';
							
						

Debounce

							
var debounce = function(func, wait, immediate) {
  var timeout, result;
  return function() {
    var context = this, args = arguments;
    var later = function() {
      timeout = null;
      if (!immediate) result = func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) result = func.apply(context, args);
    return result;
  };
};

window.addEventListener('scroll', function(){
	debounce(function(){
		//cool animation
	},100)
},false)
							
						

Lets talk workflow

						
.logo {
	animation: myAnimation 2s linear forwards;
}
@keyframes myAnimation {
  0% {
    opacity: 0;
    transform: scale(0, 0);
  }
  25% {
    opacity: 1;
    transform: scale(1, 1);
  }
  50% {
    transform: translate(0px, 0);
  }
  100% {
    transform: translate(100px, 0);
  }
}
						
					

So what happens when somebody wants the translate to take an extra 400ms?

This, basically.

donde esta la biblioteca

Velocity

Greensock/GSAP

Lib your life.

						
.logo {
	animation: myAnimation 2s linear forwards;
}
@keyframes myAnimation {
  0% {
    opacity: 0;
    transform: scale(0, 0);
  }
  25% {
    opacity: 1;
    transform: scale(1, 1);
  }
  50% {
    transform: translate(0px, 0);
  }
  100% {
    transform: translate(100px, 0);
  }
}
						
					
						
var el = document.getElementsByClassName('logo')

Velocity(el, {
    opacity: [1, 0],
    scale:[1, 0]
  },{
    duration:500,
    easing: "linear"
  }
);
Velocity(el, {
    translateY: '100px'
  },{
    duration:1000,
    delay:500,
    easing: "linear"
  }
);
						
					
						
var el = document.getElementsByClassName('logo')

TweenLite.fromTo(el, .5, {
    opacity:0,
    scale:0,
    ease:"Linear.easeNone"
  },{
    opacity:1,
    scale:1,
    ease:"Linear.easeNone",
    onComplete: function(){
      TweenLite.to(el, 1, {
        delay:.5,
        y:100,
        ease:"Linear.easeNone"
      });
    }
  }
);
						
					

Other nice-to-haves

Reverse / yoyo

Sequencing

Granular control

TweenLite.from

Workflow is important

Easier changes

More experimentation

Better work

Performance

Global timing loop for all animations

Minimizes layout thrash

Won't animate anything visually imperceptible

Another dependency

le UGH!

Don't be a stupid.

Weigh the costs and benefits.

le OMG I love libraries

Which one is raddest?

Greensock

More options and capabilites

Insane timlineing and control

A tad better performance

Big KB hit

Licensing

Best for 1 pagers, rich motion design, webGL/canvas/games/experiments

Velocity

UI only

Lighter KB hit

More approachable API

Same syntax as jQuery

100% open source & free

Plays extra well with promises

Best for UI animation in applications

TLDR:

Be aware of how your code impacts browser rendering

Test render performance as you work

Avoid $.animate and setInterval

Debounce & don't thrash

JS libs make sense in a certain set of circumstances