Efficient CSS Animations

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

The Pipeline from Markup to Graphics


><title>Web page parsing</title></head
  ><h1>Web page parsing</h1
  ><p>This is an example Web page.</p
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.


One unoptimized view
Redo everything for any DOM/style change
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


Authors might change the same element twice:

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


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


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: 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



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


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


  • 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


  • 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)


This talk
Other links
window.requestAnimationFrame for hooking in to the browser's refresh cycle