滚动穿透问题的解决方案

1,546 阅读2分钟

背景

突然看见这么一些关于这个问题的文章,然后自己之前也有对这个需求的实现,也发现在vue的vant UI框架中的浮窗对这个需求有较好的实现。所以就想结合一下这些现有的资源,深究一下问题的原因和各种解决方案,也给自己的思考留下一些记录。

首先说说什么是 滚动穿透问题

简单来说就是在触控fixed的元素时,会使document(长度大于视窗高度)一起滑动。

原因

看了挺多的资料但是没有找到具体关于这个问题的文档,但结合各种实现方式和自己的测试发现以下几个现象:

  1. 但fixed元素内有可滑动内容时,并其还未滑到边界时,不会触发body的滑动;
  2. 当网页高度不大于视窗高度时,fixed元素不会触发其父元素或其他重叠在下方元素的滑动。
  3. 当可滑动元素没有脱离文档流时,touchmove滑到边界时,会触发该边界方向的父元素滑动。

推测:document被视为fixed元素的“同一文档流的父元素”(类比现象3),导致了与现象3类似的表现,即 滚动穿透问题

解决方案

首先由上面的推测可以看出这并不是事件冒泡导致父元素touchmove默认触发的问题(如果是并不会有到边界才触发父元素滑动的问 题),所以event.stopPropagation()不是我们要的解决方案。

方案一

然后很容易我们就会想到event.preventDefault(),将不希望其滑动的父元素(主要是document)的touchmove默认行为禁止掉, 这样的确可以实现父元素不滑动,但其所有的子元素的滑动也会一并被禁止。(当浮窗内没有滑动元素时可用)。

方案二

让document变得不可滑动
当document不可滑动时,自然就没有这个问题了。实现方法有不少:

  1. 给body一个 overflow: hidden; 的样式;
  2. 把内容包裹在一个长度不大于body的可滑动元素内;

更多的这里就不补充了。

大家如果有更好的理解,希望多多指点,不吝赐教。