randomising css animations

of 59 /59
RANDOMISING CSS ANIMATIONS

Author: asjb

Post on 27-Aug-2014

625 views

Category:

Technology


1 download

Embed Size (px)

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 CSS ANIMATIONS
  • ADAM BANKIN Front 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 ANIMATIONS Why? Is this difficult?
  • Shutterstock labs home page
  • THE APPROACH Respect the separation of concerns Minimal interaction with the DOM Keep it "jank"-free
  • DAFT JANK Addy Osmani's post on jank busting
  • SEPARATION OF CONCERNS Don't write HTML Elements with JavaScript Use CSS to change appearance Use JavaScript for the rest
  • THE APPROACH (AGAIN) Respect the separation of concerns Minimal interaction with the DOM Keep it "jank"-free Can we achieve randomised CSS animations with this approach?
  • HTML Keep it simple
  • PREDEFINE YOUR DOM ELEMENTS HTML Done
  • CSS The 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 ANIMATE top/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 progress bar" "and just like that, the progress bar will animate itself up to the value set by the inline style." 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 progress bar" .bubble { animation: myAnimationName 1.2s linear 0s infinite; }
  • "and just like that, the progress bar will animate itself up to the value set by the inline style."
  • 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?
  • 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;
  • JAVASCRIPT Make it work
  • WHAT DOES JAVASCRIPT GIVE US? requestAnimationFrame/cancelAnimationFrame methods Event-type "animationend"
  • WITH PREFIXES requestAnimationFrame, msRequestAnimationFrame, mozRequestAnimationFrame, webkitRequestAnimationFrame, oRequestAnimationFrame animationend, MSAnimationEnd, webkitAnimationEnd, oAnimationEnd
  • CLASSY JAVASCRIPT var ANIMATION_CLASSES = [ // colors ['color_dark_red', 'color_red', 'color_yellow', 'color_green', 'col // translations ['translateA', 'translateB', 'translateC', 'translateD', 'translate // 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 ON When the page loads we: 1. Load custom classes "Bubble" and "BubbleController" 2. BubbleController puts all ".bubble" divs into an Array 3. 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' method 3. This method pops a Bubble instance from its pool 4. It also pops an id from the id pool 5. It creates a listener for completion of the Bubble's 'init' method 6. It creates a listener for completion of the Bubble's 'hide' method 7. 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 IN BUBBLECONTROLLER 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, bubbleInitCompleteHandle // call init on the bubble instance bubble.init({ id: id }); }
  • GAME ON ALMOST THERE Finally, the Bubble's 'init' method: 1. The Bubble instance gets the DOM Element via the id 2. Bubble creates a listener for the 'animationend' event 3. It then gets a random class from each sub-Array in ANIMATION_CLASSES 4. It saves these as a String, but doesn't set its className 5. It fires off its 'init complete' Event 6. BubbleController reacts to this and calls requestAnimationFrame. 7. requestAnimationFrame calls the Bubble instances 'show' method 8. 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 THE ANIMATION_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 IN BUBBLECONTROLLER 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 String 5. BubbleController reacts to this 6. It 'pools' the Bubble instance and 'pools' the id 7. It then runs its 'createBubble' method to start all over again
  • RE-'POOLING' THE BUBBLE AND ID IN BUBBLECONTROLLER 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 ME The bubbles are done with :before and :after They're webfonts - that's a story in itself You can pause the bubbles 'animation-timing-function' easing is done with cubic- beziers THEY'RE CLICKABLE!
  • THANKS! [email protected] @adambankin DID I MENTION WE'RE HIRING?!