You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
when you have a dialog box with scrolling content on top of a page of scrolling content, once the dialog box's scroll boundary is reached, the underlying page will then start to scroll — this is called scroll chaining.
当你开发的移动端Web应用提交测试后,细心的测试者给你提“滚动穿透”体验问题时,你会怎么处理?
我会先告诉测试者:这是移动端Web开发中很常见的问题,不影响上线,先不考虑。
然后偷偷处理它。
滚动穿透是什么
“滚动穿透”现象:
当对话框中含有可滚动内容时,一旦滚动至对话框的边界,对话框下方的页面内容也开始滚动了——这被称为“滚动穿透”。实际上,不可滚动区域,也可以被穿透,常见于“透明背景遮罩”。
MDN中相关描述为:
滚动穿透为什么存在
对于任何不可滚动的元素而言,滚动穿透是默认行为,用户在这类元素上滚动,浏览器就认为是需要滚动父元素。少数情况下,如带遮罩的弹窗,需要阻止默认行为。
而对于内部可滚动的元素而言,滚动穿透可能是多余的,但也可以视为一种浏览器的交互考虑:可滚动列表到边界了,应该滚父元素了。部分情况下,如固定定位的列表,不希望滚动穿透使页面发生滚动。
滚动的传播过程很像是冒泡过程,却不能通过阻止冒泡来阻止滚动穿透,滚动穿透因此成为一种移动端Web应用开发的经典问题。
怎么阻止滚动穿透
一种思路是阻止父元素及祖先元素滚动,一般是阻止
body
滚动,该思路的方案就有:body
设置overflow: hidden;
,在移动端会导致已滚动位置(scrollTop
)丢失,就得设法模拟和还原已滚动位置,并且必须避免在此时获取真实的已滚动位置(scrollTop = 0
)。由于实现复杂,影响广泛,不建议在生产环境中使用。另一种思路是阻止滚动穿透这一默认行为,该思路方案有:
touchmove
默认行为,来禁止滚动穿透阻止浏览器
touchmove
默认行为:该方案能够有效解决不可滚动的元素上的滚动穿透问题,但不适用于可滚动元素上,毕竟同样阻止了元素内滚动。
普遍的办法是,通过在
touchmove
事件监听回调中添加判断逻辑:列表滚动到边界后,根据touchstart
初始位置判断touchmove
方向,来决定是否阻止浏览器默认行为。使用这种方案后,在iOS上就不能玩“触底回弹”效果了,即列表到底后不能够继续上滑。
本文提出的方案
对于
touchmove
不能简单处理可滚动列表的滚动穿透问题,本文的思路是:使列表滚动不会停止在边界具体实现方案为:
描述为:当列表滚动到边界的时候,回退一段距离,使得列表可以一直被滚动。
Demo页面,其中“无尽列表”使用了本文思路的方案、“可变长列表”使用了结合
touchmove
、“无尽列表”的方案。优势
原理简单、实现简单。从触发条件出发,避免了滚动穿透。
缺点
滚动到边界结束时会有微弱的“吸附”效果,可被感知到;
视觉稿还原时有可能需要考虑腾出回退距离;
可滚动列表初始滚动位置为0,只要不开始滚动列表,就能通过下滑触发滚动穿透使页面滚动,可进一步使用
touchmove
方向判断阻止。瑕不掩瑜,这种避免滚动穿透的方案,会不会成为你的新选择?
The text was updated successfully, but these errors were encountered: