关于SO上的溢出/橡皮圈滚动主题已有多个问题,但
这就是我将这篇文章创建为知识体系的原因。
在任何其他帖子中从未提及的事情是iOS溢出滚动实际上是两部分行为。
overflow: auto/scroll
这是-webkit-overflow-scrolling: touch
元素的众所周知且通常需要的行为,其中连续/动量滚动行为越过元素容器以平滑地减慢滚动内容。
当您滚动元素的内容时,会出现动量高达足以让动量滚动超过滚动内容的长度的情况。
通过此行为,element.scrollTop
属性相应地更改为元素滚动位置并且小于0或大于最大滚动(element.scrollHeight - element.offsetHeight
)。
<body>
如果您尝试滚动已经处于其最小/最大滚动位置的任何元素甚至超过该位置(顶部向上的元素或底部向下的元素),则会发生此行为。然后滚动似乎“冒泡”到<body>
标签,并滚动整个视口。
与上述相反,element.scrollTop
属性不会更改,但document.body.scrollTop
会更改。
在这种情况下最令人恼火的是,上述两种类型之间的切换不会立即切换。
输入其中一个之后,您无法将焦点切换到任何其他元素(可滚动元素,按钮,链接......),因此滚动行为也不会改变。
例如:如果您向上滚动已经位于其顶部位置的元素,则输入
overflow scrolling type 2
并且对用户最自然的反应是尝试向下滚动。因为焦点被锁定到身体滚动而不是overflow scrolling type 1
,所以它停留在type 2
并且整个身体向下滚动。然后,典型的用户开始任意开始频繁地向上和向下滚动,而不会突破type 2
。
焦点切换以及滚动行为的改变只能在溢出动画结束且元素静止后(甚至比[0.5s]更长一些时间)发生。
因此回到上一个例子,用户的正确反应是停止触摸屏幕约1s - 1.5s然后再尝试向下滚动。
答案 0 :(得分:11)
防止元素本身溢出滚动的最基本解决方案是防止触摸事件的默认值。
document.body.addEventListener('touchmove', function(e) {
e.preventDefault();
});
然而,此方法会禁用浏览器本机动量滚动,因此不适合大多数应用程序。然而,通过一些改进(仅防止在顶部向上滚动或在底部向下滚动,...),此方法可以解决大多数问题。许多可能的实现都可以在this SO post中找到。
然而,通过上述方法不会阻止身体上的溢出滚动。
一个看似合理的可能解决方案是防止元素处于其顶部或底部位置,如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上无法可靠地运行。
然而在position: fixed
元素上设置<body>
以防止身体移动。 但是请注意这仍然不能完全阻止type 2
发生,这就是为什么有时你无法滚动/聚焦任何元素,因为在后台type2
中它的焦点锁是仍在发生(再次,在你停止触摸屏幕片刻之后它再次按预期工作)。
虽然这仍然不是最佳解决方案,但它似乎是我们在演讲时能够获得的最佳解决方案。
修改:请注意,我不确定将position: fixed
放在<body>
元素上是否安全。要跟踪我创建的following SO post可能出现的问题。显然,最好创建一个包装元素作为body的子元素,并将该元素设置为position: fixed
以避免缩放问题。
脚本iNoBounce可以创造奇迹。只需将其加载到页面并体验无反弹的Web应用程序即可。到目前为止,我还没有发现这个解决方案有任何问题。
答案 1 :(得分:1)
我认为这个问题仍然相关,所以...
请注意在身体上使用position: fixed
。它可能会产生奇怪的滚动冻结错误-实际上它仍然会“橡皮筋”,但您不会看到它。
请参阅:Div scrolling freezes sometimes if I use -webkit-overflow-scrolling
答案 2 :(得分:0)
一个不错的,简单的本地解决方案。不需要Javascript。 只需向您的孩子添加溢出滚动即可。为您的应用提供良好的原生“触感”
body{
position: fixed;
}