Monday, November 25, 2013

Scrolling at 60fps

Scrolling at 60fps

For a while people recommended to use a "noHover" class during scrolling to avoids paints that kill 60fps. Turns out that doesn't actually work because adding the noHover class causes a full style recalc which will likely completely annihilate your frame rate.

Today I saw this article, which tries to use pointer events instead to avoid the problems http://www.thecssninja.com/javascript/pointer-events-60fps
… and, indeed, it achieves great frame rates. Unfortunately it is even more broken, since it will block all clicks on your site within half a second after you stop scrolling. That might be quiet a few clicks. Fortunately we have found a way to avoid that problem:

The key insight is to use a cover div on which you toggle pointer events (or you just move it in and out of view using translate during scrolling). Then, when the user clicks the coverDiv during scrolling you can use document.elementFromPoint to get the real target:

var doc = e.target.ownerDocument;
var copy = doc.createEvent('MouseEvents');
copy.initEvent(e.type, true, true);
var realTarget = doc.elementFromPoint(e.clientX, e.clientY);
realTarget.dispatchEvent(copy);

Unfortunately there is one problem with this approach:
It doesn't work across iframes – it could be made to work in same origin iframes, but it can't be made to work with cross origin iframes. So, i.e. a click on the +1 button or a like button on your site may still be "eaten"

… which is why people should not use such hacks and instead ask browser vendors, to simply not paint during scrolling if they think that painting during scrolling is bad – which incidentally I did do :)