【问题标题】:Prevent overflow / rubberband scrolling on iOS防止在 iOS 上溢出/橡皮筋滚动
【发布时间】:2023-03-17 08:27:01
【问题描述】:

关于 SO 上的溢出/橡皮筋滚动主题已经有多个问题,但是

  1. 它们都没有提供适用于 iOS 9.3.2 上所有情况的解决方案
  2. 它们都没有提供有关问题本身的广泛而完整的信息

这就是我创建这篇文章作为知识体系的原因。


问题:

在任何其他帖子中从未提到过的是,iOS 溢出滚动实际上是一个两部分的行为。

1。使用overflow: auto/scroll 溢出滚动内容

这是-webkit-overflow-scrolling: touch 元素的众所周知且最需要的行为,其中连续/动量滚动行为越过元素容器以平滑滚动内容。

当您以足够高的动量滚动元素的内容以使动量滚动超过滚动内容的长度时,就会发生这种情况。

通过这种行为,element.scrollTop 属性会根据元素滚动位置而变化,并且小于 0 或大于最大滚动 (element.scrollHeight - element.offsetHeight)。

2。 <body>的溢出滚动

如果您尝试滚动任何已经位于其最小/最大滚动位置的元素甚至比该位置更远(顶部向上的元素或底部向下的元素),则会发生此行为。然后滚动似乎“冒泡”到<body> 标签,整个视口都被滚动了。

与上面的相反,element.scrollTop 属性不会改变,但document.body.scrollTop 会改变。

焦点锁定和行为之间的切换(1.5s 延迟)

在这种情况下最烦人的是,上述两种类型之间的切换不会立即切换。

在您输入两者之一后,您无法将焦点切换到任何其他元素(可滚动元素、按钮、链接等),因此滚动行为也不会改变。

例如:如果您向上滚动一个元素已经在其顶部位置,您输入overflow scrolling type 2,用户最自然的反应是然后尝试向下滚动。因为焦点锁定在正文滚动而不是转到overflow scrolling type 1,所以它停留在type 2,并且整个正文向下滚动。然后,典型用户开始随意开始频繁地上下滚动,而从未中断过type 2

焦点的切换和滚动行为的改变只能在溢出动画完成并且元素静止(甚至比这长一点[大约0.5s])之后发生。

因此回到前面的示例,用户的正确反应是停止触摸屏幕大约 1 秒到 1.5 秒,然后再次尝试向下滚动。

【问题讨论】:

    标签: html ios css scroll overflow


    【解决方案1】:

    解决办法:

    类型 1:

    防止元素本身溢出滚动的最基本解决方案是防止默认触摸事件。

    document.body.addEventListener('touchmove', function(e) { 
        e.preventDefault(); 
    });
    

    然而,这种方法会禁用浏览器的原生动量滚动,因此不适用于大多数应用程序。但是,通过一些改进(仅防止在顶部向上滚动或在底部向下滚动,...)此方法修复了大多数问题。在this SO post 中可以找到许多可能的实现。

    类型 2:

    但是,上述方法并不能阻止正文上的溢出滚动。

    一种似乎合理的可能解决方案是防止元素处于其顶部或底部位置,如mentioned question 上的最佳解决方案所述。

    anElement.addEventListener('touchstart', function( event ){
        if( this.scrollTop === 0 ) {
            this.scrollTop += 1;
        } else if( this.scrollTop + this.offsetHeight >= this.scrollHeight ) {
            this.scrollTop -= 1;
        }
    }
    

    然而,这在 iOS 9.3.2 上并不可靠。

    什么起作用了是在<body> 元素上设置position: fixed 以防止身体移动。 但是请注意,这仍然不能完全阻止 type 2 的发生,这就是为什么有时您无法滚动/聚焦任何元素的原因,因为在后台 type2 的焦点锁定仍在发生(再次,在您停止触摸屏幕片刻后,它会再次按预期工作)。

    虽然这仍远不是最佳解决方案,但它似乎是我们目前所能获得的最佳解决方案。

    编辑:请注意,我不确定将position: fixed 放在<body> 元素上是否安全。为了跟踪可能出现的问题,我创建了following SO post。显然,最好创建一个包装元素作为 body 的子元素并将该元素设置为 position: fixed 以避免缩放问题。


    编辑 2:确定的解决方案

    脚本iNoBounce 创造了奇迹。只需将其加载到页面并体验无反弹的 Web 应用程序。到目前为止,我还没有发现这个解决方案有任何问题。

    【讨论】:

    • 仍然存在的一个问题是 iNoBounce 不适用于应该水平滚动的内容。目前可能没有解决方案。
    • iNoBounce 只是防止下拉,进而阻止滚动,所以它破坏了一切
    • 这完全防止滚动。它将整个应用程序冻结在一个不可滚动的屏幕上。
    • 阅读插件的描述。它说You've built a nice full-screen mobile webapp, complete with scrollable elements using the -webkit-overflow-scrolling property. 您需要为要滚动的元素使用-webkit-overflow-scrolling 属性。我假设如果你想消除body 上的反弹,你需要使用绝对定位的、全宽/高度的包装 div 和 overflow: scroll
    【解决方案2】:

    我发现这个问题仍然相关,所以...

    注意在正文上使用position: fixed。它可能会出现奇怪的滚动冻结错误 - 实际上它仍然会“橡皮筋”但你不会看到它。

    见:Div scrolling freezes sometimes if I use -webkit-overflow-scrolling

    【讨论】:

      【解决方案3】:

      一个不错的、简单的本地解决方案。不需要Javascript。 只需将溢出滚动添加到您的孩子。为您的应用提供良好的原生“触感”

      body{
          position: fixed;
      }
      

      【讨论】:

      • 这并不是真正的问题解决方案。当滚动链生效时,任何滚动的子元素都不会正确滚动。
      猜你喜欢
      • 2014-06-15
      • 1970-01-01
      • 1970-01-01
      • 2014-03-06
      • 1970-01-01
      • 1970-01-01
      • 2011-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多