How to capture all scrolling events on a page without attaching an onscroll handler to every single container

The simplest way to detect all scroll events in modern browser would be using 'capturing' rather than 'bubbling' when attaching the event:

window.addEventListener('scroll', function(){ code goes here }, true)

Unfortunately as I am aware there is no equivalent in older browser such as <= IE8


I had this same issue.

The easiest way of course is to use jQuery. Be aware that this method could potentially slow down your page significantly. Also it will not account for any new elements that are added after the event is bound.

$("*").scroll(function(e) {
    // Handle scroll event
});

In vanilla JavaScript, you can set the useCapture boolean to true on your addEventListener call, and it will fire on all elements, including those added dynamically.

document.addEventListener('scroll', function(e) {
    // Handle scroll event
}, true);

Note though that this will fire before the scroll event actually happens. As I understand it, there's two phases events go through. The capture phase happens first, and starts from the page root (ownerDocument?) and traverses down to the element where the event happened. After this comes the bubbling phase, which traverses from the element back up to the root.

Some quick testing too showed that this may be how jQuery handles it (for tracking scrolls on all page elements at least), but I'm not 100% sure.

Here's a JSFiddle showing the vanilla JavaScript method http://jsfiddle.net/0qpq8pcf/


*...crickets chirping... *

OK, I guess this question isn't going to get any stackoverflow love, so I might as well answer my own question as to the best solution I've found so far, in case another user stumbles across this question:

The best solution I've come up with is to capture "onmousedown" and "onkeydown" for the BODY element: These events bubble, and so if a user tries to move a scrollbar on the page these global functions will fire as a by-product. Then, in these functions, simply look up event.target and attach a temporary "onscroll" event to those objects until the mouse/key is "up" again. Using that method, you can avoid "handler bloat" and still globally capture all "onscroll" events. (I think this will work for "mouse wheel" scrolling as well, but my research on that final wrinkle is still pending.)


The following works fine when you want to i.e. close a dialog after anything in the background is scrolled:

var scrollListener = function(e) {
    // TODO: hide dialog
    document.removeEventListener('scroll', scrollListener, true);
};

document.addEventListener('scroll', scrollListener, true);