Animations on Fire

Brian Birtles, Mozilla Japan
Graphical Web 2014, Winchester

Animation is awesome…

Source: Christopher Price 2013, https://topherchris.com/post/55109717733
UVNdotTV 2011, https://www.youtube.com/watch?v=Yg5BZARVDAs
Twitter 2011, https://www.flickr.com/photos/twitteroffice/5885172082/in/photostream/

Animation is awesome…
sometimes

Scripted animation as displayed on Firefox and Chrome on Android HTC J

setAttribute vs SVG DOM

* Times are ms taken for 100,000 iterations averaged over 5 runs (lower numbers are faster)
Browser cx
setAttribute('cx', 'X') cx.baseVal.value = X % improvement
Firefox 34 246.6 131.4 47%
Chrome 36 155.8 20.4 87%
IE 11 2347.6 1897.4 19%
  transform
  setAttribute('transform',
'translate(X, Y)')
transform.baseVal[0].
matrix.{e,f} = {X,Y}
% improvement
Firefox 34 258.4 224.8 13%
Chrome 36 199.6 30.6 85%
IE 11 1922.8 2592 -35%

More realistic test
Try using a specialized API to avoid parsing
Unoptimized
Using display:none

Using display:none

* Average result after 3~5 runs. Higher numbers are better.
Browser Unoptimized With display:none Avg. improvement
Firefox 34 25.6fps 29fps 3.4fps / 13%
Chrome 36 5.1fps 12.5fps 7.4fps / 145%
IE 11 4.8fps 7.8fps 3.0fps / 63%
Remove elements from the render tree with display:none
parapara.mozlabs.jp
Profiler in Firefox
Profiler in Chrome

Reflow logging in Firefox

Triggering layout

* Based on my inspection of profiles from this test case.
property Triggers layout?*
Firefox 34 Chrome 36 IE 11
margin-left
left (position: relative)
left (position: absolute)
transform
margin-top
transform

Avoiding reflow

Try transform instead of top/left/marginTopetc.
Try animating elements that are position:absolute.
Try non-geometric properties like color, opacity etc.
Try transform: scale instead of font-size.

Let sleeping dogs lie

What triggers recalc / reflow?

  • window.getComputedStyle(elem).color → style recalc (typically)
  • window.getComputedStyle(elem).width, elem.offsetTop, elem.getClientRects() etc. → reflow

Don't do this


for (var i = 1; i < containerElem.children.length; i++) {
  containerElem.children[i].style.top =
    containerElem.children[i-1].offsetTop + 10 + "px";
}
          

Avoiding forcing reflow

* Average result after 3~5 runs of test A and test B. Results for Firefox were particularly variable but were generally only slightly faster since the test animates the top property which does not trigger reflow in Firefox.
Browser Triggering reflow Not doing that Avg. improvement
Firefox 34 42.1fps* 45.8fps* 3.7fps / 9%
Chrome 36 10.5fps 23.2fps 12.7fps / 120%
IE 11 8.2fps 19.1fps 10.9fps / 132%
Try reading computed style (especially geometry) less often or not at all.

Paint cost

Paint area
Paint complexity

Paint flashing (Firefox)

Paint rectangles (Chrome)

Paint flashing #1

Paint flashing #2

Paint flashing #3

Paint complexity

  • box-shadow
  • border-radius
  • SVG filters…
Animating stdDeviation on <feGaussianBlur>33fps
Animating transform (scale) of blurred copy → 49fps
Try replacing expensive effects with simpler ones

Pre-rendering

Browser <iframe src="svg"> <img src="png">
Firefox 34 1.9 fps 49.5 fps
Chrome 36 11.18 fps 49.7 fps
IE 11 5.8 fps 50.9 fps
Pre-render expensive assets

Pre-rendering

* Some rendering defects
Browser <iframe src="svg"> <img src="svg"> <img src="png">
Firefox 34 1.9 fps 49.1 fps 49.5 fps
Chrome 36 11.18 fps 13.0 fps* 49.7 fps
IE 11 5.8 fps 15.5 fps 50.9 fps
Try using <img> to embed SVG images instead of <iframe> (or <object>, <embed>).

Hardware acceleration

  • Paths, text Not much
  • Filters Coming
  • Compositing OK

What gets a layer?

Animated transform
Animated opacity
3D transform

Inspecting layers

  • Firefox: about:config
    layers.draw-borders to true
    (requires layers.offmainthreadcomposition.enabled to be true)
  • Chrome: DevConsole → Rendering → Show composited layer borders

Inspecting layers

Inspecting layers

Animated transform
Animated opacity
3D transform

Layers and transitions

Layers and SVG Animation

Layers and scripted animation

Starting an animation

Enter will-change

  • will-change:<property>
    • will-change:transform
    • will-change:opacity
  • will-change:scroll-position
  • will-change:contents
  • transform:translateZ(0)
  • Firefox: need layout.css.will-change.enabled in about:config.

Applying will-change

Your browser is a jank

Compositor animation

Animation on the compositor

Not so fast…

  • Representable by compositor? (e.g. transform, opacity)
  • Supported platform? (e.g. Firefox OS)
    (layers.offmainthreadcomposition.async-animations → true)
  • Other limitations: top/left also animated?
  • Controlled by the browser? (e.g. CSS Animations)

What about script?


elem.animate({ transform: 'rotate(360deg)' },
             { duration: 1200,
               iterations: Infinity });