移动端滚动穿透

在 IOS,在弹出的 Modal(弹窗/模态窗) 层上下拖动,会发现被 Modal 遮挡的背景跟随滚动。这种现象就像是“滚动”穿透了。 除了 IOS,在小米原生浏览器也发现存在相似的问题。

这里有一个条件,就是Modal自身内容没有出现滚动条。 如果Modal存在滚动条,那么“滚动”就不会出现穿透,而是表现为 Modal 内容滚动。

有经验的开发者一定会第一时间关注到touchMove事件。和我们想的一样,它就是罪魁祸手。 简单来讲,我们可以通过.preventDefault()来解决问题。

解决方案

// 获取modal和modal的遮照
const targetEl = document.querySelector("#modal");

// 这里主要是判断targetEl的内容是否超出targetEl的高度
// 从而使得target产生滚动条
// 如果targetEl出现滚动条,那么滚动穿透Bug也就不再存在
// 此时也就不需要禁用 touchMove事件
// 如果你此时禁用了touchMove,会导致targetEl元素本身也无法滚动!
if (targetEl.scrollHeight <= targetEl.clientHeight) {
  targetEl.addEventListener("touchmove", (e) => {
    // 这个条件是仅在苹果设备上开启禁用
    if (
      window &&
      window.navigator &&
      window.navigator.userAgent.match(/iPhone|iPad/)
    ) {
      // 阻止滚动事件默认行为
      e.preventDefault();
    }
  });
}

网上有一些教程会继续指引你将事件监听挂在 document 上。但是我认为这是不对的:

  1. 第一点:因为出现“滚动穿透”这种问题的组件很少,其中不少人都只是碰到Modal这个组件。我们可以从Modal组件上解决问题,而不是将其扩散到全局。
  2. 第二点:全局监听的toucheMove可能来源于使用touchMove做手势操作的组件内。如果你依旧把这些事件当成单纯的scroll。可能会造成其他组件异常,并且非常难以查明异常原因。请记住这不是scroll事件,而是touchMove

另外,我还注意到,有教程指引读者,在判断滚动超出顶部/底部后则调用.preventDefault()。 这样的实现我认为是缺乏产品思维的,因为在一些手机上,系统默认滚动超出顶部/底部并产生阻尼效果。这些手机的用户已经习惯了系统统一的滚动行为。不允许用户滚动超出顶部/底部是破环用户使用习惯的错误解决手段。

使用 iScroll 代替原生滚动

这个方案是存在弊端的,smooth-scrollbar的作者在smooth-scrollbar的说明文档中专题添加了一篇《Caveats》提醒大家尽量不要使用 js 模拟原生滚动。另外iScroll也已经变成归档状态不再维护了。

虽然使用smooth-scrollbariScroll替换原生滚动能够彻底解决平台带来的问题。但是代价不可小觑。为了解决出现的新的性能问题,你可能还需进一步实现虚拟滚动。这其中的得失需要开发者认真衡量一番。

多说两句

会遇到这个问题,你应该是正在从事移动端网站或者 Web App 的开发。你按照我给出的方案解决后,依旧能够发现会存在一些场景下出现“滚动”穿透的问题。你一定想彻底解决它。但是解决它的最好办法是浏览器,而不是你。如果你是在一个套壳的 App 中开发网页,那么请将它交给“壳”去解决。

移动端的 Web 开发真的存在很多问题,这使得开发者无法专注于业务实现。并会有一部分人因掌握了这些特性而洋洋自得。我不认为这有什么值得骄傲的,这些问题反而恰恰说明了 Web 开发的不足。就像是“虚拟 DOM”这个技术,难道不是说明浏览器本身优化不够完美,使得“虚拟 DOM”成为一项技术?

许多优秀的开发者为这门技术作出了令人惊叹的贡献。“虚拟 DOM”降低了开发大型前端项目的心智负担;“MVVM”思想让驾驭更庞大的前端项目不再那么困难;“Typescript“让维护项目不再成为噩梦;“Webpack“等构建技术解决了开发和发布时产生的一系列问题;等等……

然而从事前端七年,我不断的惊叹于这些惊人的成果并学习它们。这也让我感受到 Web 前端技术像是打上一个个精美的布丁,然后继续负重前行。它看上去变得愈加的“复杂”,而我看他,却感觉更像是打了许多补丁的“破”袄。

我非常希望未来前端开发可以变得:专注于实现精美的 UI 和交互而不是兼容性;关注用户体验而不是框架原理。我只是想要做出好用的界面,为何要那么难?

加我微信,成为我的朋友wechat
Copyright © 2018 val-istar-guo.com All rights reserved苏ICP备2023015265号