Smooth Animation on Mobile Web

Smooth Animation on Mobile Web

Presented at Velocity Conference 2014: http://velocityconf.com/velocity2014/public/schedule/detail/34995.

With powerful smartphone platforms and high-performance web browsers, there is no more excuse for laggy UI animations on a mobile web application. The “best practice” list of client-side mobile optimization is pretty well-known: use optimized JavaScript, requestAnimationFrame, event throttling, GPU acceleration, and so on. In this talk, those best practices will be put to the test in a series of practical user interface patterns, from a silky smooth kinetic scrolling example to the use of CSS 3-D to clone the infamous Cover Flow effect.

0284b8950e0f4a57bcc092d4dbb98d97?s=128

Ariya Hidayat

June 26, 2014
Tweet

Transcript

  1. Smooth Animation on Mobile Web From Kinetic Scrolling to Cover

    Flow @ariyahidayat June 26, 2014
  2. Newton’s laws of motion

  3. Steve Jobs, 2007

  4. None
  5. None
  6. Optimized JavaScript requestAnimationFrame Event throttling

  7. ariya.github.io/kinetic #kineticscrolling https://speakerdeck.com/ariya

  8. Drag-and-Scroll 1

  9. http://ariya.github.io/kinetic/1/

  10. Text “Clipped” via overflow:hidden http://ariya.ofilabs.com/2013/08/javascript-kinetic-scrolling-part-1.html 80 lines of JavaScript Illusion

    of scrolling
  11. No Native Browser Scrolling view = document.getElementById('view'); if (typeof window.ontouchstart

    !== 'undefined') { view.addEventListener('touchstart', tap); view.addEventListener('touchmove', drag); view.addEventListener('touchend', release); } view.addEventListener('mousedown', tap); view.addEventListener('mousemove', drag); view.addEventListener('mouseup', release); Intercept mouse events Intercept touch events
  12. Steady Pressed Scrolling touchstart touchend touchmove touchend

  13. Tap vs Release function tap(e) { pressed = true; reference

    = ypos(e); e.preventDefault(); e.stopPropagation(); return false; } function release(e) { pressed = false; e.preventDefault(); e.stopPropagation(); return false; }
  14. Drag: Delta + CSS Transform if (pressed) { y =

    ypos(e); delta = reference - y; reference = y; scroll(offset + delta); } function scroll(y) { offset = (y > max) ? max : (y < min) ? min : y; view.style[xform] = 'translateY(' + (-offset) + 'px)'; }
  15. Scroll Threshold delta = reference - y; if (delta >

    2 || delta < -2) { reference = y; scroll(offset + delta); }
  16. User taps the screen pressed = true (touch) reference =

    20 (view) offset = 100 User drags 7 px up (touch) y = 13 (touch) delta = 7 (view) offset = 107 translate the document by 7 px User releases finger pressed = false
  17. Drag-and-Scroll Technique Intercept browser events Track position + apply CSS

    transform Illusion of scrolling
  18. Kinetic F/X 2

  19. http://ariya.github.io/kinetic/2/ Momentum Effect Flick List Kinetic Scrolling

  20. http://ariya.ofilabs.com/2013/11/javascript-kinetic-scrolling-part-2.html Automatic scrolling Manual scrolling 120 lines of JavaScript

  21. Steady touchstart Pressed Manual Scrolling Automatic Scrolling touchend timer tick

    touchmove touchend and zero speed touchend and positive speed timer tick decelerate to zero speed touchstart
  22. Tap Drag Release (Quick) Move Release Flick Gesture

  23. Manual Scrolling Automatic Scrolling Track touch position Scroll the view

    Compute the “launch” velocity Scroll the view Reduce the velocity
  24. Continuous Velocity Tracking function tap(e) { pressed = true; reference

    = ypos(e); velocity = amplitude = 0; frame = offset; timestamp = Date.now(); clearInterval(ticker); ticker = setInterval(track, 100); e.preventDefault(); e.stopPropagation(); return false; } Call track() 10 times/second Rate throttling
  25. Velocity = Change of Position function track() { var now,

    elapsed, delta, v; now = Date.now(); elapsed = now - timestamp; timestamp = now; delta = offset - frame; frame = offset; v = 1000 * delta / (1 + elapsed); velocity = 0.8 * v + 0.2 * velocity; } instantaneous velocity ~ 100 ms optional filter
  26. Automatic Scrolling Exponential decay time scroll offset

  27. Slow Down, a.k.a. Deceleration time velocity

  28. Stopped Decelerating

  29. None
  30. Half-Life velocity reduced to 50%

  31. Time Constant velocity reduced by 63%

  32. Scroll offset at a given time Final scroll offset Amplitude

    (how far the final scroll offset is) Time constant
  33. amplitude = 0.7 * velocity; target = offset + amplitude;

    requestAnimationFrame(autoScroll); Setup for Automatic Scrolling
  34. function autoScroll() { var elapsed = Date.now() - timestamp; scroll(target

    - amplitude * Math.exp(-elapsed / timeConstant)); requestAnimationFrame(autoScroll); } Continuous Automatic Scrolling
  35. 6 × time constant The list will stop after 1.95

    seconds
  36. The flick (=launch velocity) determines how far the list will

    stop It does not impact when the list will stop scrolling 1 2
  37. Exponential Decay vs Cubic Bézier Position Exponential decay Cubic bézier

    Velocity time time
  38. Exponential Decay vs Cubic Bézier t

  39. Frame Rate HUD in Chrome chrome://flags http://ariya.ofilabs.com/2013/03/frame-rate-hud-on-chrome-for-android.html

  40. Kinetic Scrolling Unmasked Intercept browser events Track position + velocity

    Kinetic F/X Auto scroll with exponential decay
  41. Snap-to-Grid 3

  42. http://ariya.github.io/kinetic/3/ List items Target position

  43. Date Picker The scrolling can’t stop halfway

  44. Adjustment of Final Position http://ariya.ofilabs.com/2013/12/javascript-kinetic-scrolling-part-3.html Possible choices

  45. As Simple As... function autoScroll() { var elapsed = Date.now()

    - timestamp; scroll(target - amplitude * Math.exp(-elapsed / timeConstant)); target = Math.round(target / snap) * snap; requestAnimationFrame(autoScroll); }
  46. As Simple As... function autoScroll() { var elapsed = Date.now()

    - timestamp; scroll(target - amplitude * Math.exp(-elapsed / timeConstant)); target = Math.round(target / snap) * snap; requestAnimationFrame(autoScroll); } Integer multiples of snap
  47. Hydrogen Energy Levels E Discrete levels Classical physics Quantum mechanics

  48. Swipe with Parallax 4

  49. None
  50. None
  51. http://ariya.github.io/kinetic/4/

  52. Different Distance, Different Speed http://ariya.ofilabs.com/2013/12/javascript-kinetic-scrolling-part-4.html

  53. function scroll(offset) { var slow = Math.round(offset / 2); var

    fast = Math.round(offset); ... } snap = screen width
  54. Model View Controller Kinetic Model Touch events View DOM properties

    “Number” Event Handler
  55. Cover Flow 5

  56. CSS with GPU Compositing http://ariya.ofilabs.com/2013/06/optimizing-css3-for-gpu-compositing.html

  57. http://ariya.github.io/kinetic/5/

  58. None
  59. 200 lines of JavaScript http://ariya.ofilabs.com/2014/01/javascript-kinetic-scrolling-part-5-cover-flow-effect.html No transformation translateX(-110px) translateZ(-150px) rotateY(60deg)

    translateX(110px) translateZ(-150px) rotateY(-60deg)
  60. translateX(-110px) translateX(-110px) translateZ(-150px) translateX(-110px) translateZ(-150px) rotateY(60deg) Perspective 3-D

  61. Swipe time translateX(0px) translateX(-110px) time translateZ(0px) translateZ(-150px) time rotateY(60deg) rotateY(0deg)

  62. Model View Decoupling Touch events 3-D View CSS transform

  63. Final Words

  64. Kinetic Scrolling Parallax Effect

  65. Thank You shapesecurity.com @ariyahidayat