Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

Ariya Hidayat

June 26, 2014
Tweet

More Decks by Ariya Hidayat

Other Decks in Programming

Transcript

  1. Smooth Animation on Mobile Web
    From Kinetic Scrolling to Cover Flow
    @ariyahidayat
    June 26, 2014

    View Slide

  2. Newton’s
    laws of motion

    View Slide

  3. Steve Jobs, 2007

    View Slide

  4. View Slide

  5. View Slide

  6. Optimized JavaScript
    requestAnimationFrame
    Event throttling

    View Slide

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

    View Slide

  8. Drag-and-Scroll
    1

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  12. Steady
    Pressed
    Scrolling
    touchstart
    touchend
    touchmove
    touchend

    View Slide

  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;
    }

    View Slide

  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)';
    }

    View Slide

  15. Scroll Threshold
    delta = reference - y;
    if (delta > 2 || delta < -2) {
    reference = y;
    scroll(offset + delta);
    }

    View Slide

  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

    View Slide

  17. Drag-and-Scroll Technique
    Intercept browser events
    Track position + apply CSS transform
    Illusion of scrolling

    View Slide

  18. Kinetic F/X
    2

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  22. Tap Drag
    Release
    (Quick) Move Release
    Flick Gesture

    View Slide

  23. Manual Scrolling Automatic Scrolling
    Track touch position
    Scroll the view
    Compute the “launch” velocity
    Scroll the view
    Reduce the velocity

    View Slide

  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

    View Slide

  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

    View Slide

  26. Automatic Scrolling
    Exponential decay
    time
    scroll
    offset

    View Slide

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

    View Slide

  28. Stopped
    Decelerating

    View Slide

  29. View Slide

  30. Half-Life
    velocity reduced
    to 50%

    View Slide

  31. Time Constant
    velocity reduced
    by 63%

    View Slide

  32. Scroll offset
    at a given time
    Final scroll offset
    Amplitude
    (how far the final scroll offset is)
    Time constant

    View Slide

  33. amplitude = 0.7 * velocity;
    target = offset + amplitude;
    requestAnimationFrame(autoScroll);
    Setup for Automatic Scrolling

    View Slide

  34. function autoScroll() {
    var elapsed = Date.now() - timestamp;
    scroll(target - amplitude * Math.exp(-elapsed / timeConstant));
    requestAnimationFrame(autoScroll);
    }
    Continuous Automatic Scrolling

    View Slide

  35. 6 × time constant
    The list will stop after 1.95 seconds

    View Slide

  36. The flick (=launch velocity) determines
    how far the list will stop
    It does not impact
    when the list will stop scrolling
    1
    2

    View Slide

  37. Exponential Decay vs Cubic Bézier
    Position
    Exponential decay
    Cubic bézier
    Velocity
    time
    time

    View Slide

  38. Exponential Decay vs Cubic Bézier
    t

    View Slide

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

    View Slide

  40. Kinetic Scrolling Unmasked
    Intercept browser events
    Track position + velocity
    Kinetic F/X
    Auto scroll with exponential decay

    View Slide

  41. Snap-to-Grid
    3

    View Slide

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

    View Slide

  43. Date Picker
    The scrolling can’t stop halfway

    View Slide

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

    View Slide

  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);
    }

    View Slide

  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

    View Slide

  47. Hydrogen Energy Levels
    E
    Discrete levels
    Classical physics
    Quantum mechanics

    View Slide

  48. Swipe with Parallax
    4

    View Slide

  49. View Slide

  50. View Slide

  51. http://ariya.github.io/kinetic/4/

    View Slide

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

    View Slide

  53. function scroll(offset) {
    var slow = Math.round(offset / 2);
    var fast = Math.round(offset);
    ...
    }
    snap = screen width

    View Slide

  54. Model View Controller
    Kinetic
    Model
    Touch
    events
    View DOM
    properties
    “Number”
    Event
    Handler

    View Slide

  55. Cover Flow
    5

    View Slide

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

    View Slide

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

    View Slide

  58. View Slide

  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)

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  63. Final Words

    View Slide

  64. Kinetic Scrolling
    Parallax Effect

    View Slide

  65. Thank You
    shapesecurity.com
    @ariyahidayat

    View Slide