【问题标题】:Prevent iOS bounce without disabling scroll ability在不禁用滚动功能的情况下防止 iOS 弹跳
【发布时间】:2015-07-05 20:41:33
【问题描述】:

我正在尝试实施一种解决方案,以防止当网页内容大于视口时在 Safari for iOS 中出现 iOS 反弹效果。

我正在处理的页面在结构上非常具体,与此页面非常相似http://new.salt.ch/

  • 基本结构是基于引导程序的。
  • 它在顶部有一个固定的导航栏。
  • 它具有全屏背景幻灯片。
  • 幻灯片有一个固定在视口底部的叠加层。
  • 有一个页脚元素可在画布外加载,并且仅在滚动内容时可见。
  • 内容在导航栏后面滚动。
  • 内容由位于导航栏下方 20 像素的标题和位于视口上方 20 像素的一系列按钮组成。
  • 滚动时,按钮和标题都会在屏幕上向上移动以显示页脚。

我遇到的问题与页面http://new.salt.ch/ 上的问题相同,因为当您向上滚动时,屏幕底部会出现反弹效果,并显示背景和叠加层。

我尝试了各种解决方案,包括 iNoBounce.js、Nonbounce.js 以及我在 SO 上找到的一些其他建议。

我总是遇到同样的问题...当我尝试禁用反弹时,所有滚动都会被禁用。我猜这是因为内容(页脚除外)总是足够大以至于不需要滚动,因此滚动被禁用并且页脚不再可以通过滚动访问。

【问题讨论】:

    标签: javascript jquery html ios css


    【解决方案1】:

    此代码应该停止反弹,因为它是 HTML 标记反弹

    html {
        height  : 100%;
        overflow: hidden;
        position: relative;
    }
    body {
        height  : 100%;
        overflow: auto;
        position: relative;
    }
    

    【讨论】:

    • 这个修复似乎已经过时了。 bouncefix.js 似乎也不能正常工作。
    • 如果你们能把遇到问题的版本放在上面,那么它可能有助于更新修复程序。
    • 关于这个问题的任何更新?我试过上面的代码,它在 ios 9.3.5 上不起作用
    • 在 ios12 中工作,两者都添加了position: relative
    • 这对我有用。我有一个带有水平滚动的滑块,它一直在引起轻微的反弹。
    【解决方案2】:

    如果我对您的问题的解释正确,那么多年来我们在开发跨平台移动网络应用程序时遇到了同样的问题,试图让所有不同的专有滚动功能在每台设备上都能正常工作:Apple iOS、Google Android、Windows Phone、笔记本电脑 Chrome、笔记本电脑 Safari、IE 和笔记本电脑 Edge。

    jQuery Mobile 继续尝试在他们的框架范围内解决这个问题,但它太过分了,每个设备制造商/操作系统制造商都在不断更新。

    是的,我们为每个单独的移动设备提供了解决方案。我们已经测试过,但没有认真考虑为每个设备开发设备选择性分页框架,这要求我们检测每个设备并为每个设备提供稍微不同的框架。基本上要维护至少 3 个甚至多达 12 个不同版本的代码,这真是个糟糕的主意。

    解决方案:我们最幸运的是将您的持久页眉和页脚放在您的页面框架之上。为简单起见,这是使用内联样式的一般解决方案:

    <html>
    <head>
      <title>Fixed Header and Footer on All Mobile Web Apps</title>
      <meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0" />
      <style>
        html, body { height:100%; width:100%; }
      </style>
    </head>
    <body>
    <div style="position: fixed; height:100%; width:100%; top:0; left:0;">
      <div style="height:calc(100% - 1px); width:100%; margin-top: 60px; z-index: 1; overflow-y: scroll; -webkit-overflow-scrolling: touch;">
        [Body Content That Can Scroll if it extends beyond screen...]
    
      </div>
      <div style="position: absolute; top:0; left:0; width:100%; height: 60px; background:#dddddd; z-index:10;">
        [Header Content...]
    
      </div>
      <div style="position: absolute; bottom:0; left:0; width:100%; height: 40px; background:#cccccc; z-index:11;">
        [Footer Content...]
    
      </div>
    </div>
    </body>
    </html>
    

    因此,Body 可以是任何 jQuery Mobile 页面集。事实上,理论上,Body 几乎可以是来自任何框架的任何内容。

    特别说明,带高度的行:calc(100% - 1px);对魔法至关重要。

    这个问题看似无穷无尽的组合或排列,几乎成了我们多年来的圣战,试图找到最纯粹、最简单、最普遍兼容的解决方案。因此,在为这个主题投入了大量令人尴尬的工时之后,这不仅是我们最好的解决方案,也是我们发现的唯一一种普遍兼容的方法,它还允许您只使用一个单一的代码库。它已在最新版本的 iOS、Windows Phone、Android、笔记本电脑 Chrome、笔记本电脑 Safari、PhoneGap、笔记本电脑 Firefox、IE 9-11 和 Windows Edge 上成功测试。

    标签:移动应用、网络应用、固定页眉、固定页脚、永久页眉、永久页脚、滚动问题、iOS 滚动反弹、Chrome 滚动反弹、Android 滚动反弹、webkit 滚动问题、webkit 触摸滚动、iOS 触摸滚动问题

    【讨论】:

    • 非常感谢!这就像一个魅力!我正在使用 Inobounce,当与不同的水平滚动组结合使用时,它让我非常头疼。使用此解决方案,我的 Web 应用程序的外观就像一个真正的本机应用程序。即使不使用 javascript hacks ...... :D 干杯 - 接受我的投票! :) 提示使用 calc(100% - 0.1px) 来避免实际看到 1px。 (y)
    • 杰里米,我喜欢那个解决方案。很简单。但是我遇到了一个问题。如果内容的初始滚动位置为0并且我将内容向下拖动将没有(在ios上)反弹效果并且整个滚动状态被破坏,我无法向下滚动或向上滚动。它仅在我最初向上滚动然后向下滚动时才有效。你没有遇到过这样的问题吗?
    • @AlexanderJorias 我也有同样的问题。不幸的是,标题似乎应该在其顶部有页面的滚动条。这对于 Cordova 应用程序来说似乎很尴尬。 :-/
    • @IvanBorisenko 有什么解决方案吗? :)
    • 你刚刚为我节省了整个下午的调试时间@Jeremy Whitt 真的很棒!!!!
    【解决方案3】:

    我设法解决了在移动 Safari 上支持 overflow: autooverflow: scroll 的大多数问题:

    • 在列表开头触摸后不挂起滚动视图,然后向下移动然后向上移动(在这种情况下,移动版 Safari 会为整个页面运行其默认的弹跳行为)
    • 支持顶部的固定标题/操作栏,而滚动条不会造成丑陋的重叠

    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();
      });
    
    });
    <html>
    <head>
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
    </head>
    <body id="fixedBody" style="overflow: hidden;">
      <div style="position: fixed; height: 64px; width:100%; top:0; left:0; background-color: green; z-index: 1;">
        Header
      </div>
      <div id="scrollDiv" style="position: absolute; width: 100%; top: 64px; bottom: 0px; overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; background-color: white;">
        <div style="height: 150px; background-color: blue;">
          First
        </div>
        <div style="height: 150px; background-color: red;">
          Second
        </div>
        <div style="height: 150px; background-color: green;">
          Third
        </div>
        <div style="height: 150px; background-color: black;">
          Another
        </div>
      </div>
    </body>
    </html>

    我唯一需要注意的是,当用户触摸并开始向下移动然后向上移动时,什么也没有发生(预期:列表应该向下滚动)。但至少该方法可以防止“伪向下滚动”并且不会混淆用户。

    为了克服最后一个问题,有必要模拟一个触摸结束,然后在方向改变时触摸开始事件(我已经放置了“TODO”cmets)。

    更新:可以避免在 iOS Cordova 上使用 DisallowOverscroll = trueWKWebView 修复 JavaScript 代码。

    【讨论】:

    【解决方案4】:

    我浏览了一些关于 SO 的答案,但在偶然发现这段代码之前,情况看起来很黯淡。

    html {
      position: fixed;
      height: 100%;
      overflow: hidden;
    }
    
    body {
      width: 100vw;
      height: 100vh;
      overflow-y: scroll;
      overflow-x: hidden;
      -webkit-overflow-scrolling: touch;
    }
    

    body 的样式声明可以放在您希望能够滚动的任何元素上。您还可以根据需要更改overflow-xoverflow-y。我个人需要它不要滚动到两侧,所以我这样声明。

    2017 年 9 月 15 日更新:我不得不将此修复程序用于另一个项目,并且我能够在 html 选择器上不使用这些声明 position: fixedheight: 100%;。 YMMV

    2018 年 4 月 12 日更新(在 cmets 中提到):如果您在页面上使用固定元素,这些元素在滚动时可能会出现视觉上的“抖动”。

    【讨论】:

    • +1 用于消除詹姆斯坎贝尔的回答中发生的一点垂直摆动。 -1 表示非分号和非 CSS。 :(
    • @EthanB 你的想象力一定被打破了!享受 CSS 和分号。
    • 非常感谢! :)
    • 从事 Angular 7 项目。我在 iPod(第 6 代)上进行测试,发现页面非常有弹性。从左侧滑动书写时。我可以看到当前页面后面的前几页。不好。这解决了问题。谢谢!!! :-D
    • 谢谢。我已经为此苦苦挣扎了一段时间。
    【解决方案5】:

    我使用了 iNoBounce https://github.com/lazd/iNoBounce,效果很好!

    如果您还需要允许水平滚动,santi6291https://github.com/lazd/iNoBounce/pull/36 有一个拉取请求,可以解决这个问题

    【讨论】:

      【解决方案6】:

      对于 iOS 13 上的 2019 Safari,我能够使用此修复:

         html {
            overflow: hidden;
            height: 100%;
            position: fixed;
         }
      
         body {
            overflow: auto;
            height: 100%;
            position: relative;
        }
      

      至少对我来说它涵盖了大多数情况。

      【讨论】:

      • 我还必须在html 下添加width: 100% 以保留fixed 之前的布局。
      • 在没有“位置”的情况下为我工作。谢谢!
      【解决方案7】:

      您只需将 CSS 属性 overscroll-behavior: none 添加到您的 body

      body {
        overscroll-behavior: none
      }
      

      更多详情在this article

      【讨论】:

      【解决方案8】:

      我尝试了所有 CSS 解决方案均无济于事。 iOS 在到达顶部/底部时仍然会反弹某些 div,或者在使用固定定位时滚动本身变得非常不可靠和错误。所以我想出了一个非常简单的 JavaScript 解决方案,似乎已经为我解决了:

          function onTouchStart(e) {
              // Save position of touch
              console.log("touchstart");
              const touch = e.touches[0] || e.changedTouches[0];
              window.lastY = touch.pageY;
          }
      
          function onTouchMove(e) {
              console.log("touchmove");
              // Check user isn't scrolling past content. If so, cancel move to prevent ios bouncing
              const touch = e.touches[0] || e.changedTouches[0];
              y = touch.pageY;
              if (y < window.lastY && e.srcElement.scrollTop == (e.srcElement.scrollHeight - e.srcElement.clientHeight)) {
                  console.log("user is trying to scroll down without anywhere to scroll to. Canceling propagation.");
                  e.preventDefault();
              } else if (y > window.lastY && e.srcElement.scrollTop == 0) {
                  console.log("user is trying to scroll up without anywhere to scroll to. Canceling propagation.");
                  e.preventDefault();
              }
          };
      
          document.addEventListener("touchstart", onTouchStart, { passive: false });
          document.addEventListener("touchmove", onTouchMove, { passive: false });
              
      

      【讨论】:

        【解决方案9】:

        对于离子用户 -

        对我来说一个简单的解决方案是在 ion-content 的子 div 上使用 slot="fixed"

        <ion-content>
            <div slot="fixed" />
        </ion-content>
        

        【讨论】:

          【解决方案10】:

          在我的例子中,我希望地址栏在滚动时消失,当用户滚动时我会得到弹跳效果,但这为我解决了这个问题

          html {
            position: relative;
            overflow-y: scroll;
          }
          
          body {
            overflow-y: scroll;
            overflow-x: hidden;
            -webkit-overflow-scrolling: touch;
          }
          

          【讨论】:

            猜你喜欢
            • 2012-06-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-03-08
            • 2019-02-12
            • 2021-05-12
            • 1970-01-01
            相关资源
            最近更新 更多