Prevent iOS bounce without disabling scroll ability

前端 未结 7 1243
情歌与酒
情歌与酒 2020-11-28 06:14

I am trying to implement a solution to prevent the iOS bounce effect in Safari for iOS when a web page content is larger than the viewport.

The page I am working on

7条回答
  •  庸人自扰
    2020-11-28 06:40

    I managed to solve most problems supporting overflow: auto and overflow: scroll on mobile Safari:

    • without hanging the scroll view after touching at the beginning of list, then moving down and then up (mobile Safari runs its default bouncing behavior for the whole page in that case)
    • support for fixed header / action bar on top without ugly overlapping of it by a scrollbar

    window.addEventListener('DOMContentLoaded', function () {
                            
      var atTop = true;
      var atBottom = false;
    
      var body = document.getElementById('fixedBody');
      body.addEventListener('touchmove', function(event){
        event.preventDefault();
      });
    
      body.addEventListener('touchstart', function(event){
        event.preventDefault();
      });
    
      body.addEventListener('touchend', function(event){
        event.preventDefault();
      });
    
      var scrollingDiv = document.getElementById('scrollDiv');
      if (scrollingDiv.scrollHeight <= scrollingDiv.clientHeight) {
        atBottom = true;
      }
    
      scrollingDiv.addEventListener('scroll', function(event){
        
        if (event.target.scrollTop === 0) {
          atTop = true;
        } else {
          atTop = false;
        }
        
        if (event.target.scrollHeight - event.target.scrollTop === event.target.clientHeight) {
          atBottom = true;
        } else {
          atBottom = false;
        }
      });
      
      var lastY = 0;
      var topLock = false;
      var bottomLock = false;
      
      scrollingDiv.addEventListener('touchmove', function(event){
        event.stopPropagation();
        var currentY = event.touches[0].clientY;
        if (currentY > lastY) {
          // moved down
          if (atTop) {
            event.preventDefault();
            topLock = true;
          }
    
          if (bottomLock) {
            bottomLock = false;
            // TODO: Emulate finger remove and touch again here
          }
        } else if(currentY < lastY){
          // moved top
          if (atBottom) {
            event.preventDefault();
            bottomLock = true;
          }
    
          if (topLock) {
            topLock = false;
            // TODO: Emulate finger remove and touch again here
          }
        }
         
        lastY = currentY;
      });
    
      scrollingDiv.addEventListener('touchstart', function(event){
        lastY = event.touches[0].clientY;
        event.stopPropagation();
      });
    
      scrollingDiv.addEventListener('touchend', function(event){
        event.stopPropagation();
      });
    
    });
    
    
      
    
    
      
    Header
    First
    Second
    Third
    Another

    The only caveat I have is that when user touches and starts moving down and then up, nothing happens (expected: the list should scroll down). But at least the method prevents "pseudo scrolling down" and not confuses user.

    To overcome that last problem, it's necessary to emulate a touch end and then touch start event when direction changed (I've put "TODO" comments).

    Update: it's possible to avoid using JavaScript code fix on iOS Cordova with DisallowOverscroll = true and WKWebView.

提交回复
热议问题