The last timeout solution had one major drawback: the kinetic scrolling effect can last quite a long time (even 1 second or so) ... and disabling scrolling for 1-2 seconds would not be the best solution.
Soooo, as promised, here is a different approach.
Our goal is to provide one answer for one user action, which in this case scrolls.
What a "scroll" . To solve this problem, letโs say that โscrollingโ is an event that lasts from the moment the page transition begins until the moment the movement ends .
The effect of kinetic scrolling is achieved by moving the page many times (say, every 20 ms) a short distance. This means that our kinetic scroll consists of many very small linear โscrollsโ.
Empirical testing has shown that these small โscrollsโ occur every 17-18 m in the middle of the kinetic scroll and about 80-90 ms at the beginning and at the end. Here is a simple test we can install to see that:
var oldD; var f = function(){ var d = new Date().getTime(); if(typeof oldD !== 'undefined') console.log(d-oldD); oldD = d; } window.onscroll=f;
Attention! Each time this mini-scroll occurs, a scroll event is fired. So:
window.onscroll = function(){console.log("i'm scrolling!")};
will shoot 15 to 20 times in one kinetic scroll. BTW, onscroll has really good browser support (see the compatibility table ), so we can rely on it (with the exception of touch devices, I will talk about this problem a bit later);
Some might say that overriding window.onscroll is not the best way to set event listeners. Yes, you are advised to use
$(window).on('scroll',function(){...});
or whatever you like, this is not a problem problem (I personally use my own library).
So, with the onscroll event, we can confidently say whether this particular mini-page motion belongs to one solid kinetic scroll, or is it new:
var prevTime = new Date().getTime(); var f = function(){ var curTime = new Date().getTime(); if(typeof prevTime !== 'undefined'){ var timeDiff = curTime-prevTime; if(timeDiff>200) console.log('New kinetic scroll has started!'); } prevTime = curTime; } window.onscroll=f;
Instead of "console.log", you can call the desired callback function (or event handler), and you're done! The function will be launched only once for each kinetic or simple scroll that was our goal.
You may have noticed that I used 200 ms as a criterion for whether this is a new scroll or part of a previous scroll. It is up to you to set higher values โโat 999% to prevent additional calls. However, keep in mind that this is NOT what we used in my previous answer. This is just a period of time between any two page movements (whether it is a new scroll or a small part of a kinetic scroll). In my opinion, there is very little chance that there will be a lag of more than 200 ms between steps in the kinetic scroll (otherwise it will not be completely smooth).
As I mentioned above, the onscroll event works differently on touch devices. It does not work with every small step of the kinetic scroll. But it will fire when the page movement is finally over. Moreover, there is an ontouchmove event ... So, this is not very. If necessary, I can also offer a solution for touch devices.
PS I understand that I wrote too much, so I would be happy to answer all your questions and provide additional code if you need to .
The provided solution is supported in all browsers, it is very lightweight and, more importantly, suitable not only for Mac, but also for every device that can perform kinetic scrolling, so I think this is really a way.