Efficient CSS Animations

David Baron, Mozilla
2014年06月04日, CSS Day, Amsterdam
http://dbaron.org/
@davidbaron
Slides: http://dbaron.org/talks/

The Pipeline from Markup to Graphics

Parsing

<html><head
><title>Web page parsing</title></head
><div
  ><h1>Web page parsing</h1
  ><p>This is an example Web page.</p
></div>
html head body title "Web p..." div h1 p "Web p..." "This..."

Frame tree (rendering tree)

Content Tree / DOM Tree Frame Tree / Rendering Tree Document html head body title "Web p..." div h1 p "Web p..." "This..." Viewport Scroll Block Block Block Block Block Text Text

The Pipeline from Markup to Graphics

Layer tradeoffs

With fewer layers:

  • it's more expensive to repaint each one

with more layers

  • they use more memory
  • it's more expensive to composite them together

Layerization varies between browsers.

Optimization

One unoptimized view
Redo everything for any DOM/style change
Optimizations
Skip entire steps
Skip part of a step
Coalesce changes

Optimizations can and do change.

Skipping steps

Content Match selectors Compute style Construct frames Layout Paint Composite Now shown separately

Skipping steps

Coalescing

Authors might change the same element twice:

element.style.position = "absolute";
element.style.overflow = "auto";

Coalescing

Authors might make changes where the work needed to handle one subsumes the work for the other:

element.style.backgroundColor = "aqua";
element.parentNode.style.backgroundColor = "white";

Coalescing

Browsers don't actually process the changes until:

  • It's time to redraw
  • Script asks for something (e.g., style, positions, sizes) that requires processing them

Coalescing

Coalescing: some things that flush style / frame construction

getComputedStyle(element, "").color

(Maybe Gecko-specific; might only flush style)

Coalescing: some things that flush layout

getComputedStyle(element, "").width
element.offsetTop

Coalescing

DO NOT DO THIS:

for (var i = 0; i < n; ++i) {
  var photo = document.getElementById("photo" + i);
  var label = document.getElementById("label" + i);
  label.style.top = photo.offsetHeight + "px";
}

These can sometimes be hidden in frameworks.

CSS Transitions

:link {
  background-color: #c33;
  color: white;
  transition: background-color 600ms ease;
}
:link:hover { background-color: #c00; }

CSS Animations

@keyframes bounce {
  from { transform: translateY(0em) }
  to   { transform: translateY(-2em) }
}
#ball {
  width: 0.5em; height: 0.5em;
  background: orange;
  border-radius: 50%; 
  animation: bounce 600ms infinite alternate
             cubic-bezier(0.7, 0, 1, 1);
}

Animations

I will sometimes use the word animations to refer to both CSS Transitions and CSS Animations.

Most animations

Most animations

  • No need for script
  • No worries about breaking coalescing
  • Fits the browser's refresh cycle

Animations can run on the compositor

As long as active layer is present, changes to some properties ('opacity', 'transform') can be done entirely on the compositor.

(One statement is a precondition for the other. They're not equivalent.)

Animations can run on the compositor

Optimization

  • Results will differ between browsers
  • Profiling is usually the best source of truth
  • Profiling isn't where I want it to be
  • With understanding, other techniques can also help

Experimentation

  • do main thread pauses in script pause the animations?
  • measure restyles, reflows, repaints (flashing)?
  • observe whether active layers are present
  • experiment with changing cost of a paint (e.g., blurs)
  • experiment with ...

Showing layer borders on Firefox OS (1/2)

Showing layer borders on Firefox OS (2/2)

Thanks

This talk
http://dbaron.org/talks/
Other links
window.requestAnimationFrame for hooking in to the browser's refresh cycle