Scrolling a overflow:auto; element on a touch screen device

UPDATE: this code may no longer be needed! You may want to use the CSS property -webkit-overflow-scrolling: touch instead. More details can be found on this StackOverflow post.


In mobile Safari on the iPhone, iPod Touch, and iPad (as well as the webkit based browser on Android phones) it’s not immediately obvious how to scroll a div that has overflow:auto; set on it. If this were a desktop browser you would see scrollbars and be able to manipulate those or even use your mouse wheel. No such concepts exist on a touch screen device!

To scroll the entire page you just touch it and move your finger. But when you touch the element that would normally scroll, the entire page scrolls instead. This is a little bit broken in my opinion since there’s no visual indicator that you aren’t seeing all the content. However, if you are on a site and you know there’s a scrollable div there is a simple (but not obvious) workaround. Simple use two fingers at the same time and scroll them in the same direction.

This works OK but like I said it’s not obvious, there’s still no indicator that the content is scrollable, and when you use more than one finger you might accidentally trigger some other gesture like scaling the page. I recently ran into this exact issue at work and came up with a pretty solid solution in javascript. I broke this down into two simple functions, but the last one is where the magic happens.

This first function simply attempts to create a new touch event. Only touch screen browsers like mobile Safari have these events, so if it doesn’t throw an error then we are using a touch screen device. Otherwise it’s probably a desktop browser.

 

Next, this function calls the isTouchDevice() function, and if it succeeds we attach some special touch events to the page. First when a touch event begins (the touchstart event) we get the current scroll position and prevent the default browser behavior, which in this case would be to scroll the page. Next when you move your finger the touchmove event is called. Here we just subtract the position of your finger from the scroll position we saved earlier and again prevent the page from scrolling.

So that’s it, just include these functions on your page and just call it by passing in the ID of the element you want to scroll. Like so: touchScroll("MyElement");. You can see a working demo here: http://chrismbarr.github.com/TouchScroll. I feel like this is a better way of doing things because it’s more intuitive since you’re just using one finger, and it’s potentially more obvious. Even if you don’t immediately know there’s hidden content, you might accidentally touch this while scrolling the page and realize there’s more to see in this div.

Feel free to fork or modify this code on GitHub.

130 replies

  1. Nick says:

    Dude you rock! Silly that these browsers don’t handle this type of element in a more intuitive way, considering CSS overflow is taking over what we used to use iframes for…

    Thanks much for the very concise, very functional code!

  2. Nick says:

    Oh, something you should be aware of: the try/catch block in isTouchDevice seems to have no effect.. As in all the real browsers on desktop computers (Firefox and WebKit—Chrome and Safari) don’t fail in that block and allow a TouchEvent to be created. This doesn’t seem to have any adverse effects on usability, it just could mean that this check is entirely unnecessary.

    • Chris Barr says:

      I’ve fixed the issue with the try/catch block. The if(isTouchDevice()){ was missing the parenthesis to run it as a function. This actually caused it to break pretty bad in IE as well.

      Anyway: a dumb oversight by me, but a simple fix as well.

      • Gopiinadh says:

        Hi Chris,

        Thanks for your nice post !
        But it is blocking the links default behavior of the div, and scrolling is very slow.

        Could you help me in this.

        • Gopiinadh says:

          This is working with links as well, Thank you ALL

          function touchScroll(id){
          if(isTouchDevice()){
          var el=document.getElementById(id);
          var scrollStartPos=0;
          var lastPos=0;
          var delta=0; // isn’t really a delta
          var capture=false;

          el.addEventListener(“touchstart”, function(event) {
          scrollStartPos=this.scrollTop+event.touches[0].pageY;
          lastPos = event.touches[0].pageY;
          if (capture) {
          event.preventDefault();
          capture = false;
          }
          },false);

          el.addEventListener(“touchmove”, function(event) {
          var deltaY = scrollStartPos-event.touches[0].pageY;
          delta = event.touches[0].pageY – lastPos;
          lastPos = event.touches[0].pageY;
          capture = !(delta = 0 && this.scrollTop == 0);
          if (capture) {
          this.scrollTop = deltaY;
          event.preventDefault();
          } else {
          }
          },false);
          }
          }

  3. Max says:

    Thank you so much for this code snippet, really useful!
    Do you know any way to add kinetic/momentum scroll to the scrollable div?

    Thanks!

    • Chris Barr says:

      I haven’t looked into it, but I imagine it wouldn’t be too hard to add in if you found the right algorithm.

  4. Brad says:

    The one flaw in this, at least for my application, is that I have clickable links inside my scrolling region that the touchstart event is capturing. So no clicking.

    Ideas?

    • koenahn says:

      I am having the same issue, I was hoping to find the answer here. It’s been four years since you posted… I don’t suppose you found a fix?

      • Chris Barr says:

        From what I’ve read, this fix is no longer needed on iOS 5+ devices anyway. You can use the CSS property -webkit-overflow-scrolling: touch to get the desired result. Check out this StackOverflow post.

        • anamee says:

          You can amend touchScroll like the following and add classes to the elements that you don’t want to trigger a scroll event

          function touchScroll(id, ignoreClass){
          if(isTouchDevice()){ //if touch events exist…
          var el=document.getElementById(id);
          var scrollStartPos=0;

          document.getElementById(id).addEventListener(“touchstart”, function(event) {
          if (event.target.className.indexOf(ignoreClass) === -1) {
          scrollStartPos=this.scrollTop+event.touches[0].pageY;
          event.preventDefault();
          }

          },false);

          document.getElementById(id).addEventListener(“touchmove”, function(event) {
          if (event.target.className.indexOf(ignoreClass) === -1) {
          this.scrollTop=scrollStartPos-event.touches[0].pageY;
          event.preventDefault();
          }
          },false);
          }
          }

          It is a bit crude but it works. I’m sure you can think of other better ways to do this.

  5. Opinion8ed says:

    Wow.  I developed our site with desktop in mind.  Bought the iPhone 4 and most of the site renders correctly.  Then I tried to scroll a long list (client list) and couldn’t!  I panicked.  Finally found your page and it’s amazing that the double-finger parallel scroll works for scrolling the div!  Whew!  Didn’t want to make some hack or patch.  Since the “double flick” seems to work, it’s odd that Apple wouldn’t include that in their basic gesture manual.  I’d rather just tell someone the site works fine and they just need to use the “standard” gesture than make some unnecessary patches.  As for no visible scrollbars, that’s a problem.  Mine is cutting the middle of content so it’s kind of obvious, but I can see a break in white space would cause problems. 

    I can see, though, why iPhoneOS gets confused with the gestures.  I don’t see why they wouldn’t show scrollbars in overflow DIVs though!!  What’s the logic there???

  6. Tobias Naess says:

    Thanks for sharing Chris – this was a great solution!

    As Brad pointed out, there’s a problem with links, or even nested touch events. Do you have any ideas how to cope with this?

  7. Jesse says:

    Hey thanks for the code example, works like a charm.
    @Brad & Tobias Naess
    I found that removing the event.preventDefault() part of the code in the touchstart event allows me to click buttons and links normally

  8. An Chi says:

    Thanks Chris – nice solution. And Jesse for discovering how to make buttons and links work.

  9. Ryan Frederick says:

    @Max @ChrisBarr You could use Modernizr to determine if the browser supports touch events. Off the top of my head, you could use:
    if ( $(‘html’).hasClass(‘touch’) ) { touchScroll(#element); }

    • Chris Barr says:

      True, and I am a fan of Modernizr, but if you only want to detect touch events (as in my use case) an entire library that does other things can be a bit overkill.

  10. Kelly Wood says:

    Hello, How exactly do you get the error:

    Line: 56
    Error: Object doesn’t support this property or method

    …to stop on your example?  In your example here:  https://www.chris-barr.com/files/touchScroll.htm

    In IE 8, if errors are turned on, it fails.  Can you tell me why?

    Thanks in advance.

  11. Kelly Wood says:

    forgive me, maybe I’m stupid.  I don’t see where you changed it.  Help please.

    Kelly

  12. Kennedy says:

    Do you know if there is a way to make this work scrolling horizontal?

  13. Dave Santorum says:

    Chris, this is very smart and works perfectly on the default Android (2.3.2) browser – with just one finger! Very useful – google/cyanogen/mobile webkit builders should take note!

  14. Chris says:

    You are officially my code hero of the day. Thank you!

  15. Hi,

    I was looking for tween/easing support of Chris function above. So I made this integration with the lightweight popular JSTweener lib:

    http://pastebin.com/MRA5hQ1R

    (download jstweener @ http://coderepos.org/share/wiki/JSTweener)

    Eventhough it worked great, I discovered webkit-tweening on the iphone has slightly higher framerates.
    So I already abandonded the idea above, however its a great non-webkit-easing addition.
    (Who knows somebody can use it in the future)

  16. Cyberdemon8 says:

    Yayyyy!!! you’re a damned god!!! =D

    for( i=0; i<1000; i++) {
      echo "Thank you!";
    }

  17. Steve says:

    Thanks Chris, you saved my bacon!

    I just checked a site I’ve spent the entire night working on (now 6:30am) and found it doesn’t work on Android 2.2.1 browser. Even the twin finger thing doesn’t work.

    Your code allows the list to scroll again. Now I just have to make something that looks like a scroll bar appear.

  18. Ashish TYagi says:

    Thanx a lot to Chris and Jesse . :)

  19. Jeff says:

    Chris, I think I created a more complete touchScroll function by using the help on this page.  It allows x scrolling if need be also:

    function touchScroll(id){
        if(isTouchDevice()){ //if touch events exist…
            var el=document.getElementById(id);
            var scrollStartPosY=0;
            var scrollStartPosX=0;
    
            document.getElementById(id).addEventListener(“touchstart”, function(event) {
                scrollStartPosY=this.scrollTop+event.touches[0].pageY;
                scrollStartPosX=this.scrollLeft+event.touches[0].pageX;
                //event.preventDefault(); // Keep this remarked so you can click on buttons and links in the div
            },false);
    
            document.getElementById(id).addEventListener(“touchmove”, function(event) {
                // These if statements allow the full page to scroll (not just the div) if they are
                // at the top of the div scroll or the bottom of the div scroll
                // The -5 and +5 below are in case they are trying to scroll the page sideways
                // but their finger moves a few pixels down or up.  The event.preventDefault() function
                // will not be called in that case so that the whole page can scroll.
                if ((this.scrollTop < this.scrollHeight-this.offsetHeight &&
                    this.scrollTop+event.touches[0].pageY < scrollStartPosY-5) ||
                    (this.scrollTop != 0 && this.scrollTop+event.touches[0].pageY > scrollStartPosY+5))
                        event.preventDefault(); 
                if ((this.scrollLeft < this.scrollWidth-this.offsetWidth &&
                    this.scrollLeft+event.touches[0].pageX < scrollStartPosX-5) ||
                    (this.scrollLeft != 0 && this.scrollLeft+event.touches[0].pageX > scrollStartPosX+5))
                        event.preventDefault(); 
                this.scrollTop=scrollStartPosY-event.touches[0].pageY;
                this.scrollLeft=scrollStartPosX-event.touches[0].pageX;
            },false);
        }
    }
    

  20. ciin says:

    Thank for coding

  21. siju says:

    everything is good,But no links are working(eg:<a href="http://www.google.com">siju</a>)…
    What i do?,i want this link is workng cde…

  22. MEESO says:

    Hi,
    Actually this code was amazing to fix my problem but it disabled all onclick events into my page how can I enable clicks into the scrollable div can anyone help me please?

    Thnx…

  23. Michael says:

    @meeso:
    quickfix: if you removed
    event.preventDefault();
    from the “touchstart” block, then links do work, a downside being that you need to tap into a scrolling area first to the be able to scroll then – I guess it should be done better

  24. Lakshmi says:

    Thanks a ton!!! This has really solved my probelm

  25. greg says:

    @Jeff – awesome work extending the original (and already very cool) solution.
    Thank you both.

  26. Nicolas says:

    You simply rocks !!!
    Thanks :)

  27. Cormac says:

    Great code Chris.  I have integrated it with jQuery 1.4+ and Modernizr to shorten the code somewhat.  The function below uses the jQuery live() function which means it can also be used with elements that are created by Javascript after DOM loading:

    function touchScroll(selector)
    {
        if (Modernizr.touch) {
            var scrollStartPos = 0;
            $(selector).live('touchstart', function(event) {
                event.preventDefault();
                scrollStartPos = this.scrollTop + event.originalEvent.touches[0].pageY;
            });
            $(selector).live('touchmove', function(event) {
                event.preventDefault();
                this.scrollTop = scrollStartPos - event.originalEvent.touches[0].pageY;
            });
        }
    }

  28. DrMad says:

    More than a year after your first post, still useful !
    I love those slick and simple solutions.
    Thanx a bunch !

  29. Jeff_ says:

    here is a jQuery plugin to do so

        $.fn.touchScroll = function(options) {
            var isTouchDevice = function(){try{document.createEvent(‘TouchEvent’);return true;}catch(e){return false;}};
            if (isTouchDevice()) {
                this.data(‘scrollStartPos’,0);
                this.bind(‘touchstart’,function(event){$(this).data(‘scrollStartPos’,$(this).scrollTop()+event.originalEvent.touches[0].pageY);event.preventDefault();});
                this.bind(‘touchmove’,function(event){$(this).scrollTop($(this).data(‘scrollStartPos’)-event.originalEvent.touches[0].pageY);event.preventDefault();});
            }
        }

  30. MK says:

    Doesn’t seem to work inside a colorbox :(

  31. Paul says:

    Jeff_ or anyone! Is there a working example of the jQuery plugin. It does not seem to work for me

  32. Mark says:

    Excellent job Chris! (And other guys who left valuable comments/additions!) I ran into the links issue, but noticed that had been covered in the comments as well. Thanks for sharing (and saving me hours of frustration)!!

    Cheers,
    Mark

  33. Alex says:

    Hi, i have try this for a div on a mobile website, the scroll work right but i can’t make work the link in the div =(

  34. sky says:

    Great solution guys, thanks to all contributors to this thread.

  35. Andy Mercer says:

    Given that iOS 5 now supports overflow:scroll, I naively thought I could just use that and be done. Then I tried my page on an Android 2.3 device and discovered the error of my ways. Thank you for this script! It’s certainly made my life easier.

  36. Swapna says:

    Thanks Chris.. this solved my problem.

  37. Uday says:

    This was working fantastically until ice-cream sandwich came along. Now it’s freezing.

  38. saurabh says:

    For me it works fine but problem is I have to tap once to make it scrollable is there anyway to prevent this erraneous behaviour

    please suggest

    thanks in advance

  39. TL says:

    Hi there, I try to help a friend of mine to implement this code to his existing older page without luck. Maybe you can get in touch with me by e-mail to cross check where our problem is.
    Thank you in advance.

  40. This worked great! Made my site work well.

    Only problem is, I’ve just upgraded my Galaxy Note to Ice Cream Sandwich and it’s broken.

    I’m gonna take a look into it and see what’s different between the android OS

  41. Lyubo says:

    Hey… More than 2 years since you’ve posted this and it still saves sombody’s soul (mine as example).

    Thank you!

  42. michael says:

    Saved my as* dude.. Thanks a millionth tone

  43. Thanks. You’re an as* saver :)

  44. Peter says:

    It seems does not work on Android 4.0.4 :(

  45. Lazza says:

    Here’s Jeff’s better solution in Jquery version, partially based on Cormac’s code:

    function touchScroll(selector) {
        if (isTouchDevice()) {
            var scrollStartPosY=0;
            var scrollStartPosX=0;
            $(“body”).delegate(selector, ‘touchstart’, function(e) {
                scrollStartPosY=this.scrollTop+e.originalEvent.touches[0].pageY;
                scrollStartPosX=this.scrollLeft+e.originalEvent.touches[0].pageX;
            });
            $(“body”).delegate(selector, ‘touchmove’, function(e) {
                if ((this.scrollTop < this.scrollHeight-this.offsetHeight &&
                    this.scrollTop+e.originalEvent.touches[0].pageY < scrollStartPosY-5) ||
                    (this.scrollTop != 0 && this.scrollTop+e.originalEvent.touches[0].pageY > scrollStartPosY+5))
                        e.preventDefault();
                if ((this.scrollLeft < this.scrollWidth-this.offsetWidth &&
                    this.scrollLeft+e.originalEvent.touches[0].pageX < scrollStartPosX-5) ||
                    (this.scrollLeft != 0 && this.scrollLeft+e.originalEvent.touches[0].pageX > scrollStartPosX+5))
                        e.preventDefault();
                this.scrollTop=scrollStartPosY-e.originalEvent.touches[0].pageY;
                this.scrollLeft=scrollStartPosX-e.originalEvent.touches[0].pageX;
            });
        }
    }

    Be sure to call the function from inside $(document).ready().

  46. Adam says:

    Man, you rock! I thought this was impossible!

  47. craig-c says:

    I’m trying to use this on two scroll panels in the same page, but regardless of what I do with the code I can only get one of the panels to scroll on a mobile device.  One panel always remains non functional when it comes to scrolling and this is when both panels need to scroll.  Do you have any suggetions for resolving this problem.  Thanks in advance.

  48. Lazza says:

    @craig-c if you use Jquery, grab my version of the code (two comments above yours) and give any elements you want to scroll a class, let’s say “scrollable”. Then call the function like this:
    touchScroll(”.scrollable”);
    As I mentioned before, be sure to call it inside $(document).ready().

  49. Lazza says:

    Also pay attention to the “fancy quotes” which are put by WordPress, you need to use standard quotes, otherwise the code will break.

  50. craig-c says:

    Thanks guys.  However, after having a second look I realised the problem was with the scrollStartPos variable in the touchScroll function.  I’ve therefore changed that so I have a separate version of that variable for each scroll list.  I’ve also duplicated the addEventListener calls (one pair of function calls for each scroll list).  Anyway, all is now working fine.  Thanks again

  51. Scott says:

    Wow, Thank you so much for that great code. I had a scrolling div that didn’t work on android, of course, and this function worked perfectly for me. Great Quick fix for my project, thanks again!!!!!

  52. mark says:

    thanks for the great code. now a user can scroll the content in the div.
    but only user with a galaxy s II have to touch the dots on the side of the div box that they can slide the content. many people don’t see the dots.
    does someone has the same problem and a solution for this?
    thanks

  53. clmmatteo says:

    With this system the scrollbar is hidden, giving problems for users to notice there’s more content if they scroll.
    However if we add, in the CSS, the ::-webkit-scrollbar… options to cutomize the scrollbars, they magically appear both in Android and iOs (at least with the devices I tried).
    If this works not only on my three devices but also on other ones, I think we almost resolved the overflow problem – scrollbars included :)

  54. Lazza says:

    clmmatteo: the scrollbars don’t exists at all on some Android versions AFAIK, but if they appear correctly on some devices it could be nice to try them. :)

  55. Brahmesh says:

    Dude you rock!

  56. Pete says:

    Really liked that I found this for a website I administer.  That is until my Droid4 got upgraded to Ice Cream Sandwich (ICS) last night.  Now if it works, it is very jittery.

    It’d be great if this could be modified to work on ICS.

    Back to square one for me.

  57. Luciano says:

    Thanks for this solution it is very useful!

    Like SIJU (comment 24) and MEESO (comment 25), I have links and buttons in my div which won’t work anymore.

    If I take off the event.preventDefault() from the touchStart block, it is not working (Although I tap on the area first).

    Any help with that??

    Thanks

  58. DHall says:

    Simply wonderful! Thank you!

  59. Clemens says:

    Should this also work for Android 2.3.x?

    I tried but was not successful …

  60. Lazza says:

    Clemens, yes it works. At least, my version on comment #48 runs smoothly. You can try it live by scrolling a long formula on this page (on the horizontal direction of course):
    http://giovani.mathesisvicenza.it/forum/topic.php?id=363

  61. JATIN MARWAH says:

    @Lazza Thanks Man, your code worked amazingly, I should say this is the full proof solution that you have given, this scroll was not working in the android initially as we had a div inside a popup overlay in mobile, and using your snippet it worked.

    Just two things I would like to highlight here is
    1) Irrespective of where your function is placed in the JS but function call should be made within $(document).ready() itself.
    2) Unlike the original chris-barr’s code, in this you need to pass “#yourelementid” or “.yourelementclass” without the relevant prefixes this won’t work.

    Be careful with the syntax and Happy coding !!
    Cheers

  62. Clemens says:

    Ciao Andrea,
    have you tried this very code on a 2.2/2.3-Android in vertical direction?

    Looks like

    e.originalEvent.touches[0].pageY
    (and
    e.originalEvent.touches[0].pageX)

    always return 0

    Grazie mille
    Clemens

  63. Lazza says:

    Clemens, it works, try it here with your device: http://fiddle.jshell.net/df7n8/2/show/
    Please note that, as I said, the code I posted in comment 38 suffers the “fancy quotes” effect. You can copy the code from the fiddle here if you prefer: http://fiddle.jshell.net/df7n8/2/
    Jatin, I’m glad it worked. Your comment is absolutely right, and I think it’s a good reminder for everyone who wants to use my solution. :) Using a combination of custom selectors (all Jquery selectors work) and the delegate method allows a more versatile solution which works even for elements which are “added in the future”. Thanks to Jeff and Cormac for providing much of the code I put together, I just added the delegation.

    • pjack says:

      I would actually change delegate to .on() as recommended by jQuery instead of delegate or live(which is deprecated).

  64. tomasofen says:

    Nice solution. But i think there is a usability issue with this aproach.

    If you zoom in to see only the scrolable div, then you can’t get out from it becouse no further zoom out is possible.

    Ideas to solve this are wellcome.

    Tom.

  65. Lazza says:

    A website with a good mobile layout shouldn’t have the need to zoom in/out. It shouldn’t even be possible if you correctly set the viewport to block this feature.

  66. tomasofen says:

    I deeply desagree with your vision of no-zoom sites. Zoom is there for some reason (and accesibility can be one of them). I fully dislike mobile specific sites, and i always use the “view as in desktop” check on mobile browsers.

    Anyway, the zoom behaviour exists, and this usability problem too.

    Cheers,
    Tom

  67. Lazza says:

    Zoom is there for a specific reason: a lot of sites don’t have a mobile specific version or a responsive layout (which is the best option). So if you are designing your website and your doing it the right way (responsive) then the user will not zoom it, he/she will be able to read it comfortably.
    BTW do you get the same problem also with my version of the JS or only with the one in the blog post?

  68. Clemens says:

    Ciao Lazza, maybe I am dumb?( ;) ), but

    http://fiddle.jshell.net/df7n8/11/show

    and

    http://fiddle.jshell.net/df7n8/12/show

    behave alike. Both do NOT scroll (vertically) the div but the browser.

    Testing on a Samsung Galaxy S2 with 2.3.6

    What am I missing?

  69. Lazza says:

    Clemens, your div does NOT have overflow. It hasn’t got a fixed height so the whole content is displayed. If you want to scroll it, then you need to have something to scroll in the first place. ;)

  70. Jatin says:

    Lazza’s code worked very well, but there is a issue that exists now in devices which have both touch as well as trackpad like blackberry, in that case the trackpad touch does not work, this can be due to the fact that we are preventing the defaults within that but no concrete solution I am able to find as of now. Please advise.

  71. Jatin says:

    Just to make a note, that the non touch devices which only has trackpad or trackball, this function does not interfere in that and everything works normally with clicks from trackpad.

  72. Clemens says:

    >your div does NOT have overflow
    bingo! :-)
    Thx
    Clemens

  73. ali says:

    Great, thanks

  74. Kay says:

    Much appreciated.

  75. ingredients1 says:

    Great touch-screen scroll code!! I’m using it in a project of mine and it works really well!

    Just one thing I would like to point out though, is that for the line document.getElementById(id).addEventListener("touchstart", ……….

    Why not just replace document.getElementById(id) with the “el” var that was created earlier (which is probably why the variable was created in the first place)? It made no difference to me when I did that, and it shortens the code a tiny bit as well :)

  76. Alex says:

    Thank you for your code.
    I’ve a tagboard on a forum where people paste links too.
    It wasn’t working with Android, don’t know if nowadays there’s some more clean css solution but your script is still working fine, I just done some change for the two issues: “full screen” and “link click” (at least on the second click should work).

    function touchScroll(id){
        if(isTouchDevice()){
            var el=document.getElementById(id);
            var scrollStartPos=0;
            var lastPos=0;
            var delta=0; // isn't really a delta
            var capture=false;
    
            el.addEventListener("touchstart", function(event) {
                scrollStartPos=this.scrollTop+event.touches[0].pageY;
                lastPos = event.touches[0].pageY;
                if (capture) {
                  event.preventDefault();
                  capture = false;
                }
            },false);
    
            el.addEventListener("touchmove", function(event) {
                var deltaY = scrollStartPos-event.touches[0].pageY;
                delta = event.touches[0].pageY - lastPos;
                lastPos = event.touches[0].pageY;
                capture = !(delta < = 0 && this.scrollTop+this.clientHeight==this.scrollHeight) && !(delta >= 0 && this.scrollTop == 0);
                  if (capture) {
                      this.scrollTop = deltaY;
                      event.preventDefault();
              } else {
              }
            },false);
        }
    }
    
  77. s-m says:

    Hi,

    This may be a stupid question, but how can I change this code to work in all the divs on the site? Now I can get it to work only in one element.

    Thanks!

  78. Lazza says:

    s-m, if you’re using my version from comment #48 (which I suggest you do) you can use ANY Jquery selector, for example touchscroll(“div”) for every div present or future in a page.

  79. s-m says:

    Thanks Lazza!

    I don’t know if it’s working yet, I don’t have an Android in my hand.. But what did you mean by “Be sure to call the function from inside $(document).ready()” ?

  80. Lazza says:
  81. Kaktus says:

    It doesn’t work on Samsung Galaxy S III, any ideas?

  82. RayOne says:

    It does work on my Asus Transformer. Thx a lot for sharing this code !

  83. Aaron says:

    i found a small bug but with the help of a friend we were able to get it fix. What was happening is that on Android 2.2 devices that visited a website with multiple overflow rules it would scroll but not let you click with that div. We found out by removing the preventDefault from the ‘touchstart’ event let it finish and then you could both scroll and click on multiple divs. Here is the updated code:

    function touchScroll(id){
      if( isTouchDevice() ){ //if touch events exist...
        var el = document.getElementById(id);
        var scrollStartPos = 0;
    
        document.getElementById(id).addEventListener("touchstart", function(event){
          scrollStartPos = this.scrollTop + event.touches[0].pageY;
          //event.preventDefault(); <-- This line can be removed
        }, false);
    
        document.getElementById(id).addEventListener("touchmove", function(event){
          this.scrollTop = scrollStartPos - event.touches[0].pageY;
          event.preventDefault();
        },false);
      }
    }
    • pjack says:

      Hate to break it to you but that was found a few of years ago. If you read some of the previous comments, like comment #26, you would see that removing preventDefault allowed links to work. :)

  84. craig-c says:

    Hi,

    I set up and started using your code in a website a few months back (this was actually in August of 2012). To begin with the code seemed to work fine and all my users were happy with it. However, recently I’ve found problems with getting links to work in the part of the page that’s set up to touch scroll. Therefore, please let me know if there is a way of resolving this.

    The page that I’m using this feature on is the main page in an online diary. In that page I have two scrolling lists of diary entries. Each list contains entries from a different date.

    A user can click or touch any of the entries in these lists to open up an edit page that allows them to modify the entry. There can be many entries in each list, each of which is set up as a link that works as I’ve described above.

    Everything works fine for users on PC, etc, but users on iPad and iPhone, who need the touch-scroll feature have problems activating the links on diary entries. 99% of the time, the links just don’t work, so users on mobile devices are currently unable to access the edit pages from those devices.

    I realise that this issue may have been discussed previously, but there are so many discussions listed in your page and I don’t have time to read through all of them. Therefore please give me some info on resolving this or point me to a previous discussion that does that.

    Thanks for your time.

    • Chris Barr says:

      Yes, the discussions here have gotten fairly large now! I honestly haven’t been following it that closely, but I believe someone here has made headway in getting links within the scrollable content to work for touchscreen devices. But, it also appears that newer version of iOS and Android have made it so that normal scrolling of these elements can be done with one finger – no extra code needed. So as a first step, maybe try just removing this code completely and testing it out then.

      • craig-c says:

        Hi Chris,

        After submitting my question I had a read through the other questions/answers in this page. As a result of doing that I found a comment with a time & date as follows:
        September 8, 2010 at 7:12 am

        In that comment the writer said that removing the ‘event.preventDefault()’ line(s) in the touchstart event solved the problem so that links worked. I tried that and it really does work, so you may want to test this for yourself and maybe put a comment about it with the code at the top of the page.

        Thanks for your feedback

  85. I’m pretty sure you could just check for window.TouchEvent instead of creating an event like that (which is actually deprecated). Also my phone (Android 4.0) doesn’t notice scrollLeft being changed. It ignores it.

  86. Nick says:

    I have a iPad application with a KendoUI Accordion which has scrolling. After applying this solution the accordion works fine but I can’t expand Accordion items. any help would be appreciated.

    http://stackoverflow.com/questions/17585612/kendoui-accordion-not-getting-expanded-in-ipad

  87. Pingback:Binary App Dev: Apps | Workaround for Android Overflow Bug

  88. Pingback:Workaround for Android Overflow Bug | BlogoSfera

  89. john says:

    I ahve used this code in my app and it works for the first time only. But when I revisit the page it stops scrolling. Any Idea ?

  90. David says:

    I tried your Demopage on my HTC Wildfire S (Android 2.3.5), but it doesn’t work with the standard android browser -.-

  91. Anonymus says:

    This is a great solution for the pageslide. Thanks.

  92. Kiko Herrsc says:

    thank you soooo much man! you rock!!

  93. François J. says:

    Did anyone make it work inside a ColorBox?
    I tried to bind touchScroll(document.getElementById(“cboxLoadedContent”)); to cbox_complete without any luck…

  94. Rivi says:

    i try it first in my phone before using it,
    and i so disappointed to discover that is not working

    i using Alcatel oneTouc

  95. Rivi says:

    I used the code and it works amazing
    Thanks for everything

  96. Ian Onvlee says:

    There’s quite a lot said here and I need some time to check them all out. The solution given here is still necessary. I call the function with the ontouchstart attribute of the div of the scrollable area.The problem with clickable links inside the scrollable area, I solved by simply using the ontouchend attribute, which works just as fine for links, so I don’t have to remove event.preventDefault from touchstart which creates other problems we don’t want. Hope this helps

  97. tnt-rox says:

    On many android devices if preventDefault is not set on touchstart the device assumes native scrolling and stops sending touch events to webview. If preventdefault is set on touchstart all native scrolling is disabled. The only known way to overcome this behavior is to user this shim : https://github.com/TNT-RoX/android-swipe-shim

  98. Thanks so much for the code. I used it to scroll horizontally, so modified scrollTop to scrollLeft, pageY to pageX, and seems to work great! You rock man. I love your photos too. I used to live in Nashville, TN, and some of those photos reminded me/made me miss the south!

    peace out!

  99. nosheen says:

    worked perfect, instead of using plugins, this snippet is beautiful.

  100. Samko Yoon says:

    Thanks so much! I’ve been struggling with this for a whole day and this solved my problem!

  101. nathanstaton says:

    You sir saved my A#$ I was struggling on this one and the particular device I was debugging doesn’t allow scrolling within modals however with this it does now :)

    • nathanstaton says:

      BTW, if I could make one improvement. I would, on both lines that have the preventDefault() I would be more explicit because in my case preventing the default action killed all the anchor tags so instead I went with event.touches[0].preventDefault(); for both “touchstart” and “touchmove”

  102. Accra Shepp says:

    Hey thanks for the great code! It was a life-saver.

  103. MJHd says:

    You are literally THE MAN!
    I will link to you in my humans.txt :D
    Where do I donate???

  104. Ansar Hameed says:

    O Man… you are great.
    You wrote it in 2010 it is still helping people by the end of 2015.
    I tried many things which failed unless i reached your post. Great Job :)

  105. Ettienne Pro says:

    I want this functionality on a desktop size device. You know using the mouse wheel scroll to navigate the page.. Normally with mouse wheel it takes long long to scroll down about 20 scrolls and even longer for blogs.. The mobile device flick up and down would be epic if used on a mouse wheel so if you scroll down fast it’ll do the same as mobile and when you want to stop at a point you just scroll up..

    Perhaps that behavior can be archived only on your own website, so maybe it needs to e a browser extension..

  106. Bob says:

    Really helpful. Thank you!

  107. ankiewicz84 says:

    Oh my word!!!.. you saved my life! I just spent the last 5 hours trying to figure out what the issue was, reading that this method wasn’t needed because of CSS updates, yup, that wasn’t true at all!!

    Anyone utilizing this code please note: The code above will stop all clicks occurring in these sliders. Be sure to delete the prevent.default. Other then that this code works perfectly!

    “` function isTouchDevice(){
    try{
    document.createEvent(“TouchEvent”);
    return true;
    }catch(e){
    return false;
    }
    }

    function touchScroll(id){
    if(isTouchDevice()){ //if touch events exist…
    var el=document.getElementById(id);
    var scrollStartPos=0;

    document.getElementById(id).addEventListener(“touchstart”, function(event) {
    scrollStartPos=this.scrollTop+event.touches[0].pageY;

    },false);

    document.getElementById(id).addEventListener(“touchmove”, function(event) {
    this.scrollTop=scrollStartPos-event.touches[0].pageY;

    },false);
    }
    }

    touchScroll(“YOUR_ID_GOES_HERE”);“`

  108. Paul says:

    I like the first part of the solution. Stopping the window scroll on in-div scroll initiation (mousedown event for the overflow element). The touch screens I have seen scroll both the div and the page, just the page moves more and faster, and definitely breaks the experience.

    So, I will see if a freeze (or active setting page scroll y to 0 ) solves this issue alone. This would work in any browser then, not needing to support touch events.

  109. Daniel says:

    Just want to say it’s 2018 and this is still saving lives.

    I modified it into a React vertically scrolling carousel component that was scrolling the whole page instead of just the carousel on mobile ios devices.

    I found that removing both of the preventDefaults meant that on ios the scrolling still chained up making the whole page scroll. But by removing just the first preventDefault() in the touchStart addEventListener function it allowed items to be clicked AND stopped the scroll-chaining.

    Also I removed the line: var el=document.getElementById(id); — because the variable is never used and React nags you about that sort of thing :-)

    Thank you!!!!

Leave a Reply