防止在iOS上溢出/橡皮筋滚动 [英] Prevent overflow / rubberband scrolling on iOS

查看:2071
本文介绍了防止在iOS上溢出/橡皮筋滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于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.5秒)



在这种情况下最令人恼火的事情是



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


一个元素已经在它的顶部位置,你输入溢出滚动类型2 ,一个用户最自然的反应是,然后尝试向下滚动回来。因为焦点锁定到主体滚动而不是转到溢出滚动类型1 ,它保留在类型2 全身向下滚动。然后,典型的用户随后开始任意地开始频繁地上下滚动,而不会突破类型2

$ <$ p $ c>。


焦点的切换,因此滚动行为的变化只能发生在溢出动画完成后,元素仍然静止(甚至更长[0.5s左右])。


因此回到前面的例子,用户的正确反应将是停止触摸屏幕约1s-1.5s,然后尝试滚动向下。



解决方案

解决方案:



类型1:



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

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

然而,此方法禁用浏览器本机动量滚动,因此不适合大多数应用程序。然而,有一些细化(只防止如果顶部向上滚动或底部向下滚动,...)此方法修复大多数问题。许多可能的实现都可以在此SO帖子中找到。



类型2:



上面的方法不能防止在主体上溢出滚动。



似乎合理的一个可能的解决方案是防止元素在顶部或底部位置,如在上述问题

  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 请注意,这仍然不能完全停止键入2 ,因此有时您无法滚动/聚焦任何元素,因为在后台 type2 ,它的焦点锁定仍然发生(再次,你停止触摸屏幕一会儿,它再次按预期工作)。



虽然这还远远不是最佳的解决方案,但似乎是我们能说的最好的解决方案。



修改:请注意,我不确定是否可以将位置:固定放在< body> 元素。要跟踪可能的问题,我已创建遵循SO post 。显然,最好创建一个包装器元素作为body的子元素,并将该元素设置为 position:fixed 以避免缩放问题。






编辑2:确定解决方案



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


There are already multiple questions on the topic of overflow/rubberband scrolling on SO but

  1. none of them provides a solution working for all cases on iOS 9.3.2
  2. none of them gives extensive and complete information on the problem itself

which is why I created this post as a body of knowledge.


The problem:

The thing that was never mentioned in any other post is that iOS overflow scrolling is actually a two part behaviour.

1. Overflow scrolling of content with overflow: auto/scroll

This is the commonly known and mostly wanted behaviour of a element with -webkit-overflow-scrolling: touch where the continuous/momentum scrolling behaviour goes past the elements container to slow the scrolled content down smoothly.

It happens when you scroll the content of an element with a momentum high enough for the momentum scrolling to go past the length of the scrolled content.

With this behaviour the element.scrollTop property changing accordingly to the elements scroll position and being less than 0 or bigger than the maximum scroll (element.scrollHeight - element.offsetHeight).

2. Overflow scrolling of <body>

This behaviour occurs if you try to scroll any element already at its minimum/maximum scroll position even further than that (an element at top upwards or element at bottom downwards). Then the scroll seems to "bubble up" up to the <body> tag and the whole viewport is scrolled.

In contrary to above here the element.scrollTop property does not change but document.body.scrollTop changes instead.

Focus lock and switching between behaviours (1.5s delay)

The most irritating thing in this context is that the switch between the two types described above does not switch instantly.

After you enter one of both you cannot switch focus onto any other element (scrollable elements, buttons, links, ...) and thereby the scrolling behaviour does not change as well.

For instance: if you scroll a element already at its top position upwards you enter overflow scrolling type 2 and the most natural reaction for a user is to then try to scroll back down. Because the focus is locked to the body scroll instead of going to overflow scrolling type 1 it stays in type 2 and the whole body is scrolled downwards. The typical user then starts to arbitrarily starts to scroll up and down frequently without ever breaking out of type 2.

The switch of focus and thus the change of scrolling behaviour can only occur after the overflow animation has finished and the element stands still (even a bit longer [around 0.5s] than that).

thus going back to the previous example the correct reaction of the user would be to stop touching the screen for around 1s - 1.5s and then try to scroll downwards again.

解决方案

The solution:

Type 1:

The most basic solution to prevent overflow scrolling on the element itself is to prevent default on touch events.

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

This method however disables the browsers native momentum scroll and is thereby not suitable for most applications. With some refinement however (only prevent if at top scrolling up or at bottom scrolling down, ...) this method fixes most problems. Many possible implementations can be found in this SO post.

Type 2:

Overflow scrolling on the body however is not prevented by methods described above.

One possible solution which seems reasonable is to prevent the element from ever being at its top or bottom position as described as best solution on 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;
    }
}

This however did not reliably work on iOS 9.3.2.

What did work however is setting position: fixed on the <body> element to prevent the body from moving. Please note however that this still does not completely stop type 2 from happening, which is why sometimes you cannot scroll/focus any element because in the background type2 with its focus lock is still happening (again, after you stop touching the screen for a moment it again works as expected).

While this is still far from being the optimal solution it seems to be the best we can get for the time speaking.

Edit: Please note that I am not sure if it is safe to put position: fixed on a <body> element. To track possible issues I have created following SO post. Apparently it might be better to create a wrapper element as child of body and set that element to position: fixed to avoid zoom problemes.


Edit 2: The definite solution

The script iNoBounce works wonders. Just load it to the page and experience a bounce-free web application. So far I have not found any problems with this solution.

这篇关于防止在iOS上溢出/橡皮筋滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆