Forums

The forums ran from 2008-2020 and are now closed and viewable here as an archive.

Home Forums CSS Prevent body scrolling when the user scrolls on fixed position div Reply To: Prevent body scrolling when the user scrolls on fixed position div

#266424
schkolne
Participant

Hey this has been a very helpful thread thanks everyone! I have been working on a scrollable overlay that shows in iOS on top of a regular page. I managed to get the scroll to work for the overlay well, turning off the scroll for the underlying page, using overflow-y technique. However I ran into a strange glitch.

It is related to this problem — http://blog.christoffer.online/2015-06-10-six-things-i-learnt-about-ios-rubberband-overflow-scrolling/ — but slightly different and I did a slightly different fix.

My issue in particular was that, when I scrolled down to the bottom of my overlay, it would rubber band just fine. But after it rubber-banded and came to rest, if i tried scrolling it again, the overlay would NOT rubber-band as one would expect. Instead the underlying content scrolled while the overlay remained frozen in place. This would happen for a while, usually until the underlying content rubber-banded on the other side of the screen. At which point, suddenly my overlay would start scrolling again.

I debugged this pretty heavily but couldn’t make sense of it. It seemed to be related to a weird resize event, but that wasn’t consistent. I tried to stop the event from propagating to the underlying body, but that somehow didn’t stop the underlying body from scrolling. It was as if the overlay was processing a scroll, but visually it wasn’t moving instead the other stuff was.

Anyway I did come up with a fix. My basic solution was to trap and ignore the user trying to rubberband the detail in this way. Instead, I just cancelled the events. This gave me most of the goodness of iPhone style momentum scrolling, with none of the weird buggy stuff.

well I had this detailManager thing which i used to hold a variable

var $detailManager = {
  // used for iOS touchstart/touchmove issue fix
  touchStartY        : 0,

when the overlay detail is shown, i add some events to explictly catch when the user is trying to rubberband the detail overlay in either direction, and event.preventDefault() to cancel. The below code is in my showDetail() handler:

    $detail.bind('touchstart', function(event) {
      $detailManager.touchStartY = event.originalEvent.touches[0].clientY;
    });

    $detail.bind('touchmove', function(event) {
      var touchY = event.originalEvent.changedTouches[0].clientY;

      var scrollTop = $(this).scrollTop();
      var totalScroll = $(this).prop('scrollHeight');
      var currentScroll = scrollTop + $(this).outerHeight();

      // at we're at the top of page, and moving down, disable this event
      if (scrollTop === 0 && touchY > $detailManager.touchStartY) {
        event.preventDefault();
      }
      // similarly disable if we're at the bottom of the page, and moving up
      else if (currentScroll === totalScroll && touchY < $detailManager.touchStartY) {
        event.preventDefault();
      }
    });

and for good measure, I put the below in my hideDetail() handler:

        // remove these event handlers for good measure
        // we don't want to add multiple handlers if we click this again
        $detail.unbind('touchstart');
        $detail.unbind('touchmove');

I spent way too much of my life on this bug, I hope this helps someone else out.