randomising css animations

Post on 27-Aug-2014

635 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

This was from a talk I gave at New York Front End Coders in July 2013 on how to create random CSS Animations. CSS Keyframe Animations are definitions in CSS that outline the CSS properties to be animated and the points in time during the life of the animation that these animations should be achieved. This can lead to huge amounts of CSS when trying to make something appear random. This talk sought to explain how randomisation (of a sort) was achieved. Hopefully the slides themselves can communicate this.

TRANSCRIPT

RANDOMISING CSSANIMATIONS

ADAM BANKINFront End Engineer at Shutterstock

14 years experience with HTML, CSS and JS

AUSTRALIAN (z === "zed"); // true

"ize".replace(/z/, "s");

(r === "ahhhhhh"); // true

$("#shrimp").on("barbie", function () { console.error("racial stereotype"); console.error("and frankly, I'm offended");

return false; });

RANDOMISING CSS ANIMATIONSWhy? Is this difficult?

Shutterstock labs home page

THE APPROACHRespect the separation of concernsMinimal interaction with the DOMKeep it "jank"-free

DAFT JANK

Addy Osmani's post on jank busting

SEPARATION OF CONCERNSDon't write HTML Elements with JavaScriptUse CSS to change appearanceUse JavaScript for the rest

THE APPROACH (AGAIN)Respect the separation of concernsMinimal interaction with the DOMKeep it "jank"-free

Can we achieve randomised CSS animations with thisapproach?

HTMLKeep it simple

PREDEFINE YOUR DOM ELEMENTS <div id="bubble_source"> <div id="bubble_0" class="bubble"></div> <div id="bubble_1" class="bubble"></div> <div id="bubble_2" class="bubble"></div> <div id="bubble_3" class="bubble"></div> <div id="bubble_4" class="bubble"></div> <div id="bubble_5" class="bubble"></div> <div id="bubble_6" class="bubble"></div> … <div id="bubble_15" class="bubble"></div> </div>

HTML… Done

CSSThe syntax of CSS Keyframe Animations

AT-RULE AND NAME @keyframes myAnimationName {...}

… WITH PREFIXES @-webkit-keyframes myAnimationName {...} @-moz-keyframes myAnimationName {...} @keyframes myAnimationName {...}

WITH KEYFRAMES @keyframes myAnimationName { from { background-position: 0 0; }

to { background-position: -162px 0; } }

MDN has a list of animatable properties

CHOOSE THE RIGHT PROPERTIES TO ANIMATEtop/left | translate

Paul Irish's post on using translate instead of top/left

WITH PERCENTAGE-BASED KEYFRAMES @keyframes myAnimationName { 0% { background-position: 0 0; }

100% { background-position: -162px 0; } }

MIXED VALUES IN KEYFRAMES @keyframes myAnimationName { 0% { background-position: 0 0; }

23% { opacity: 0; background-position: -162px 0; }

100% { opacity: 1; } }

TARGETING PREFIXED PROPERTIES @-webkit-keyframes myAnimationName { 0% {-webkit-transform-origin: 0 0;} 100% {-webkit-transform-origin: 25px 0;} }

@-moz-keyframes myAnimationName { 0% {-moz-transform-origin: 0 0;} 100% {-moz-transform-origin: 25px 0;} }

@keyframes myAnimationName { 0% {transform-origin: 0 0;} 100% {transform-origin: 25px 0;} }

ATTACHING A DEFINED KEYFRAME ANIMATION .classWithAnimation { animation: myAnimationName 1.2s linear 0s infinite; }

... WITH PREFIXES .classWithAnimation { -webkit-animation: myAnimationName 1.2s linear 0s infinite; -moz-animation: myAnimationName 1.2s linear 0s infinite; animation: myAnimationName 1.2s linear 0s infinite; }

SHORTHAND PROPERTIES EXPANDED /* shorthand */ .bubble { animation: myAnimationName 1.2s linear 0s infinite; }

/* expanded */ .bubble { animation-name: myAnimationName; animation-duration: 1.2s; animation-timing-function: linear; animation-delay: 0s; animation-iteration-count: infinite; }

and that's just some of them

… at MDNthere are more

*AHEM*… PREFIXED /* let's now call it 'bubble' */ .bubble { -webkit-animation-name: myAnimationName; -webkit-animation-duration: 1.2s; -webkit-animation-timing-function: linear; -webkit-animation-delay: 0s; -webkit-animation-iteration-count: infinite; }

ARE WE THERE YET?CSS Keyframe Animations, they:

define a start… the inbetween frames… and the end?

THE END IS NOT THE END"omit the to or 100% declaration from the@keyframe…"

"then you call the animation on the progressbar…"

"and just like that, the progress bar willanimate itself up to the value set by the inlinestyle."

Chris Coyer's post on animating to an inline style

"omit the to or 100% declaration from the@keyframe…"

@keyframes myAnimationName { 0% {background-position: 0 0;} }

"…then you call the animation on the progressbar…"

.bubble { animation: myAnimationName 1.2s linear 0s infinite; }

"…and just like that, the progress bar willanimate itself up to the value set by the inlinestyle."

<div id="bubble_0" class="bubble" style="background-position: -162px 0;"></div>

DOES IT NEED TO BE INLINE?What if the properties were set in a class ruleset?

/* css */ @keyframes myAnimationName { 0% {background-position: 0 0;} } .bubble { animation: myAnimationName 1.2s linear 0s infinite; } .background-move { background-position: -162px 0; }

Then the class was dynamically applied to the DOM Element?

<!-- html --> <div id="bubble_0" class="bubble background-move"></div>

RULESET AS INLINE STYLE /* Keyframe Animation definitions */ @-webkit-keyframes lightBlue { 0% { color: #2ed0e5; -webkit-transform: translate(0, 50px) scale(.2, .2); -webkit-transform-origin: 20px 0; } 14% { color: #2ed0e5; -webkit-transform: translate(0, -100px) scale(.3, .3); -webkit-transform-origin: 43px 0; } } @-moz-keyframes lightBlue { 0% { color: #2ed0e5; -moz-transform: translate(0, 50px) scale(.2, .2); -moz-transform-origin: 20px 0; } 14% { color: #2ed0e5; -moz-transform: translate(0, -100px) scale(.3, .3); -moz-transform-origin: 43px 0; } } @keyframes lightBlue { 0% { color: #2ed0e5;

JAVASCRIPTMake it work

WHAT DOES JAVASCRIPT GIVE US?requestAnimationFrame/cancelAnimationFrame methodsEvent-type "animationend"

… WITH PREFIXESrequestAnimationFrame, msRequestAnimationFrame,

mozRequestAnimationFrame,webkitRequestAnimationFrame, oRequestAnimationFrame

animationend, MSAnimationEnd, webkitAnimationEnd,oAnimationEnd

CLASSY JAVASCRIPT var ANIMATION_CLASSES = [ // colors ['color_dark_red', 'color_red', 'color_yellow', 'color_green', 'color_dark_pink' // translations ['translateA', 'translateB', 'translateC', 'translateD', 'translateE' // origins ['originA', 'originB', 'originC', 'originD', 'originE', 'originF'], // durations ['time_1500', 'time_1800', 'time_2000', 'time_2500', 'time_2700'], // easings ['easing_1', 'easing_2', 'easing_3'], // names ['light_blue', 'mid_blue'] ];

GAME ONWhen the page loads we:

1. Load custom classes "Bubble" and "BubbleController"2. BubbleController puts all ".bubble" divs into an Array3. It then makes two 'object pools'4. One has "Bubble" instances, the other is ids from each div in

the Array

OBJECT POOLS ON HTML5ROCKS

Colt McAnlis's post on Object Pools in JS

GAME ON…Then:

1. BubbleController runs a loop creating setTimeouts at+200ms

2. The interval calls BubbleController's 'createBubble' method3. This method pops a Bubble instance from its pool4. It also pops an id from the id pool5. It creates a listener for completion of the Bubble's 'init'

method6. It creates a listener for completion of the Bubble's 'hide'

method7. It runs the Bubble's 'init' method, with the id property

OBJECT POOL CODE IN BUBBLECONTROLLER // ̀bubbles̀ is an Array of Dom Elements // ̀bubbleClass̀ is Bubble function createObjectPools (bubbles, bubbleClass) { var j = bubbles.length; var bubbleArgs = { delegateName: NAME };

while (j--) { // populate the individual bubble's ids into an Array idPool[j] = bubbles[j].id;

// use an Object Pool to create enough instances to control each bubble bubblePool[j] = new bubbleClass(bubbleArgs); } }

'CREATEBUBBLE' METHOD INBUBBLECONTROLLER

function createBubble () { // get new bubble instance id form the pools var bubble = bubblePool.pop(); var id = idPool.pop();

// listen for the end of the new bubble's init phase $.subscribe(NAME + EVENTS.INIT + STATUS.COMPLETE + id, bubbleInitCompleteHandler);

// call init on the bubble instance bubble.init({ id: id }); }

GAME ON… ALMOST THEREFinally, the Bubble's 'init' method:

1. The Bubble instance gets the DOM Element via the id2. Bubble creates a listener for the 'animationend' event3. It then gets a random class from each sub-Array in

ANIMATION_CLASSES4. It saves these as a String, but doesn't set its className5. It fires off its 'init complete' Event6. BubbleController reacts to this and calls

requestAnimationFrame.7. requestAnimationFrame calls the Bubble instances 'show'

method8. The 'show' method attaches the classlist, starting the

animation

'INIT' METHOD IN BUBBLE Bubble.prototype.init = function (args) { // add inited variables this.id = args.id; this.node = doc.getElementById(args.id); this.$node = $(this.node); this.classList = 'bubble on';

// add listeners addListeners(this); setClassList(this);

$.publish(this.delegateName + EVENTS.INIT + STATUS.COMPLETE + this.id, [this]); };

RANDOMISING THROUGH THEANIMATION_CLASSES ARRAY

function setClassList (instance) { var j = ANIMATION_CLASSES.length;

while (j--) { instance.classList += (' ' + randomValue(ANIMATION_CLASSES[j])); } }

function randomValue (arr) { var length = arr.length; var idx = (Math.random() * length) | 0;

return arr[idx]; }

CALLING REQUESTANIMATIONFRAME INBUBBLECONTROLLER

function bubbleInitCompleteHandler (e, bubble) { $.unsubscribe(e.type, bubbleInitCompleteHandler);

win.requestAnimationFrame(function () { bubble.show(); }); }

'SHOW' METHOD IN BUBBLE Bubble.prototype.show = function () { // appending the classes makes the bubble appear and the animation run this.node.className = this.classList; };

GAME OFF'animationend' event

1. The Bubble reacts to the DOM Element's 'animationend'event

2. It changes the className of the DOM Element to "splat"3. It runs its 'hide' method and fires off 'hide complete'4. Inside the 'hide complete' Event is the id as a String5. BubbleController reacts to this6. It 'pools' the Bubble instance and 'pools' the id7. It then runs its 'createBubble' method to start all over again

RE-'POOLING' THE BUBBLE AND ID INBUBBLECONTROLLER

function bubbleAnimationCompleteHandler (e, bubble, id) { // add the completed bubble and its id back into the pools bubblePool.unshift(bubble); idPool.unshift(id);

createBubble(); }

SO!!!Did it work?

Labs home page

TIME ESCAPES METhe bubbles are done with :before and :afterThey're webfonts - that's a story in itselfYou can pause the bubbles'animation-timing-function' easing is done with cubic-beziersTHEY'RE CLICKABLE!

THANKS!abankin@shutterstock.com@adambankin

DID I MENTION WE'REHIRING?!

top related