jQuery scroll() detect when user stops scrolling

Ok with this..


I can tell when someone is scrolling from what I understand. So with that I am trying to figure out how to catch when someone has stopped. From the above example you can see I am removing a class from a set of elements while the scrolling is occurring. However, I want to put that class back on when the user stops scrolling.

The reason for this is I am intent on having a layover show while the page is scrolling to give the page a special effect I am attempting to work on. But the one class I am trying to remove while scrolling conflicts with that effect as its a transparency effect to some nature.

$(window).scroll(function() {
    clearTimeout($.data(this, 'scrollTimer'));
    $.data(this, 'scrollTimer', setTimeout(function() {
        // do something
        console.log("Haven't scrolled in 250ms!");
    }, 250));


I wrote an extension to enhance jQuery's default on-event-handler. It attaches an event handler function for one or more events to the selected elements and calls the handler function if the event was not triggered for a given interval. This is useful if you want to fire a callback only after a delay, like the resize event, or such.

It is important to check the github-repo for updates!


;(function ($) {
    var on = $.fn.on, timer;
    $.fn.on = function () {
        var args = Array.apply(null, arguments);
        var last = args[args.length - 1];

        if (isNaN(last) || (last === 1 && args.pop())) return on.apply(this, args);

        var delay = args.pop();
        var fn = args.pop();

        args.push(function () {
            var self = this, params = arguments;
            timer = setTimeout(function () {
                fn.apply(self, params);
            }, delay);

        return on.apply(this, args);
}(this.jQuery || this.Zepto));

Use it like any other on or bind-event handler, except that you can pass an extra parameter as a last:

$(window).on('scroll', function(e) {
    console.log(e.type + '-event was 250ms not triggered');
}, 250);


(this demo uses resize instead of scroll, but who cares?!)

Using jQuery throttle / debounce

jQuery debounce is a nice one for problems like this. jsFidlle

$(window).scroll($.debounce( 250, true, function(){
$(window).scroll($.debounce( 250, function(){

The second parameter is the "at_begin" flag. Here I've shown how to execute code both at "scroll start" and "scroll finish".

Using Lodash

As suggested by Barry P, jsFiddle, underscore or lodash also have a debounce, each with slightly different apis.

}, 150, { 'leading': true, 'trailing': false }));

}, 150));

Rob W suggected I check out another post here on stack that was essentially a similar post to my original one. Which reading through that I found a link to a site:


This actually ended up helping solve my problem very nicely after a little tweaking for my own needs, but over all helped get a lot of the guff out of the way and saved me about 4 hours of figuring it out on my own.

Seeing as this post seems to have some merit, I figured I would come back and provide the code found originally on the link mentioned, just in case the author ever decided to go a different direction with the site and ended up taking down the link.


    var special = jQuery.event.special,
        uid1 = 'D' + (+new Date()),
        uid2 = 'D' + (+new Date() + 1);

    special.scrollstart = {
        setup: function() {

            var timer,
                handler =  function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {
                    } else {
                        evt.type = 'scrollstart';
                        jQuery.event.handle.apply(_self, _args);

                    timer = setTimeout( function(){
                        timer = null;
                    }, special.scrollstop.latency);


            jQuery(this).bind('scroll', handler).data(uid1, handler);

        teardown: function(){
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid1) );

    special.scrollstop = {
        latency: 300,
        setup: function() {

            var timer,
                    handler = function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {

                    timer = setTimeout( function(){

                        timer = null;
                        evt.type = 'scrollstop';
                        jQuery.event.handle.apply(_self, _args);

                    }, special.scrollstop.latency);


            jQuery(this).bind('scroll', handler).data(uid2, handler);

        teardown: function() {
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid2) );


I agreed with some of the comments above that listening for a timeout wasn't accurate enough as that will trigger when you stop moving the scroll bar for long enough instead of when you stop scrolling. I think a better solution is to listen for the user letting go of the mouse (mouseup) as soon as they start scrolling:

    var stopListener = $(window).mouseup(function(){ // listen to mouse up
        $('#scrollMsg').html('STOPPED SCROLLING!');
        stopListner(); // Stop listening to mouse up after heard for the first time 

and an example of it working can be seen in this JSFiddle

You could set an interval that runs every 500 ms or so, along the lines of the following:

var curOffset, oldOffset;
oldOffset = $(window).scrollTop();
var $el = $('.slides_layover'); // cache jquery ref
setInterval(function() {
  curOffset = $(window).scrollTop();
  if(curOffset != oldOffset) {
    // they're scrolling, remove your class here if it exists
    if($el.hasClass('showing_layover')) $el.removeClass('showing_layover');
  } else {
    // they've stopped, add the class if it doesn't exist
    if(!$el.hasClass('showing_layover')) $el.addClass('showing_layover');
  oldOffset = curOffset;
}, 500);

I haven't tested this code, but the principle should work.

function scrolled() {
    //do by scroll start
        //do by scroll end
    }, 500)

very small Version with start and end ability

Ok this is something that I've used before. Basically you look a hold a ref to the last scrollTop(). Once your timeout clears, you check the current scrollTop() and if they are the same, you are done scrolling.

$(window).scroll((e) ->

  scrollTimer = setTimeout((() ->
    if $(this).scrollTop() is currentScrollTop
  ), animationDuration)

  currentScrollTop = $(this).scrollTop()

ES6 style with checking scrolling start also.

function onScrollHandler(params: {
  onStart: () => void,
  onStop: () => void,
  timeout: number
}) {
  const {onStart, onStop, timeout = 200} = params
  let timer = null

  return (event) => {
    if (timer) {
    } else {
      onStart && onStart(event)
    timer = setTimeout(() => {
      timer = null
      onStop && onStop(event)
    }, timeout)


yourScrollableElement.addEventListener('scroll', onScrollHandler({
  onStart: (event) => {
    console.log('Scrolling has started')
  onStop: (event) => {
    console.log('Scrolling has stopped')
  timeout: 123 // Remove to use default value

please check the jquery mobile scrollstop event

  alert("Stopped scrolling!");

For those Who Still Need This Here Is The Solution

      var t;
      function checkScroll(){
          t = setTimeout(function(){
             alert('Done Scrolling');
          },500); /* You can increase or reduse timer */

This should work:

var Timer;
    // do somethings

    Timer = setTimeout(function()
        console.log('scrolling is stop');

Here is how you can handle this:

    var scrollStop = function (callback) {
        if (!callback || typeof callback !== 'function') return;
        var isScrolling;
        window.addEventListener('scroll', function (event) {
            isScrolling = setTimeout(function() {
            }, 66);
        }, false);
    scrollStop(function () {
        console.log('Scrolling has stopped.');
<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">

This detects the scroll stop after 1 milisecond (or change it) using a global timer:

var scrollTimer;

    //Do  what you want whilst scrolling

function afterScroll(){
    //I catched scroll stop.