All you knew about javascript animation is wrong

Written by Alex Wolkov

Ok, atleast all I knew. And it’s in firefox, IE8 and Opera. But still… bare with me :

A little history about browser rendering. The are 3 browser events that happen depending on stuff you change dynamically with JS in DOM.

  1. restyle – recalculation of style for affected DOM element.
  2. reflow – recalculation of flow and all the Elements that are affected by your change.
  3. repaint /redraw – re-rendering of the element in it’s new position, style, whatever you changed.

These “events” happend each time you change something. I’m going to talk about repaint/redraw today.

When you animate a div for instance, each step in the animation, each frame if you will, fires a repaint function in the browser, that makes sense,  as the browser has to show us the updated position/style/whatever of the element.

You would suspect that a browser only repaints the individual animated element, and maybe its surrounding and dependent elements. And you would be right.

So why does some of your animation on the more heavy sites stugger in firefox and IE and Opera when they work like a charm in webkit browsers? Faster browser? Faster Rendering Engine?

All these are a factor, but there’s a hidden factor that you didn’t know about.

float:left;

“OMG? WTF? float? what’s float has to do with animation ??? Alex stop beating around and explain this to me” you must be saying.

It turns out that whenever you animate a div on a page, even if it’s position:relative, that if one of it’s ancestors has a floating (left or right), firefox/opera/ie8 fire a repaint function on ALL THE ANCESTORS content. Not Only the animated div.

So if for instance you have a tiny div that animates every 2 seconds, for every frame of that animation, firefox/opera/ie8 repaint the entire DOM tree up until the floated ancestor.

I don’t know wheather it’s a bug, or this is just how it’s suppose to be. But facts are facts.

I’ve created a small jsfiddle in order to test this.

http://fiddle.jshell.net/JeGKR/10/show/light/

The css3 stuff is there only to make the content heavy so you really notice the animation changes.

Run the animation with task manger open. Then click “add float:left” and see the difference. If you have a fast computer, click on “add content” a couple of times.

Workarounds :

There’s one workaround I’ve read about and it’s just disabling float:left on the ancestors up until the body Element. This won’t be applicable in many many cases I’m afraid.

I’ve yet to find another solution beside putting all the animated elements in a non floated container and positioning them accordingly.

Notes : if you want to see the redraw regions in firefox by yourself, you can download and install  firebug paint events

Credits : This post is a partial translation/adoption from Sergey Chikuyonok – all credits on this find go to him.

https://addons.mozilla.org/en-US/firefox/addon/9620/Fire