前言

相信大家搜css touch-action很容易搜到一批文章,但感觉自己还是需要写下自己这这个过程中的一些探索经历。

之所以写,是因为单独去学知识点或者单独看一篇文章其实很简单的,难的是在自己实践中,因为一个问题找一个方案,然后又引起另外一个问题,而这个不断发现问题的过程非常低效,需要各种尝试和理解。

使用css touch-action的原因

在其官方的说明中:是否,以及以何种方式,给定的区域,可以由用户通过触摸屏操作(例如,通过平移或缩放内置的浏览器功能)

但我最初并不是因为这个来使用它的,后续会补充一篇使用这个特性做出来的效果。我用这个属性是因为自己在使用antd-mobile的走马灯时候,在控制台代码警告,内容是这样的:

[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See…
复制代码

看到这样的报错,作为程序员,职业病肯定是要查看原因的,虽然不影响正常使用。经过查阅,其简单的描述就是这样的:Passive event listeners,做了移动端的优化。看完一脸懵逼。其实就是是否阻止默认事件200ms延迟然后再执行滚动行为,而之前的fastclick就是通过去掉这部分来避免点击延迟的。

For instance, in Chrome for Android 80% of the touch events that block
scrolling never actually prevent it. 10% of these events add more than
100ms of delay to the start of scrolling, and a catastrophic delay of
at least 500ms occurs in 1% of scrolls.
复制代码

想知道更多,可以参考这篇,写的比较详细了: 移动Web滚动性能优化: Passive event listeners

然后知道原因不够,解决方案是什么?

能搜到的方案是两种,一种是通过css方式,一种是通过js的方式。 css方式:比较简单

touch-action:none 
复制代码

js方式:在touch的事件监听方法上绑定第三个参数{ passive: false }

elem.addEventListener(
  'touchstart',
  fn,
  { passive: false }
);
复制代码

使用touch-action之后,问题来了

然后当然是开心的用第一种方案把这行css写到全局中,结果就带来了灾难。 什么问题呢?就是ios基本都可以的,但是安卓中的页面滚动都没了。这是为什么呢?这个就要看下touch-action的更官方的触摸说明了。

默认情况下,平移(滚动)和捏手势由浏览器独占处理。当浏览器开始处理触摸手势时,使用的应用程序Pointer_events将收到一个pointercancel事件。 通过明确指定浏览器应该处理哪些手势,应用程序可以为其余手势提供自己的行为,pointermove并pointerup为其余的手势提供监听器。应用程序使用Touch_events。 通过调用禁用浏览器处理手势preventDefault(),但也应该使用触摸动作来确保浏览器在调用任何事件侦听器之前知道应用程序的意图。当手势开始时,浏览器将触摸元素及其所有祖先的触摸动作值与实现手势的触摸动作值(换句话说,第一个包含滚动元素)相交。 这意味着在实践中,触摸动作通常只应用于具有一些自定义行为的单个元素,而不需要在该元素的任何后代上明确指定触摸动作。手势开始后,触摸动作值的更改将不会对当前手势的行为产生任何影响。

文档参考来源:touch-action

说人话

这段话阐明的就是触摸事件整个的进行过程,既然它可以通过css来约定滚动的行为,那么就意味着你写了touch-action:none,就会导致原来的页面滚动失效了。这就是安卓上无法页面滚动的原因。

为什么ios没有受影响呢,我觉得可能是ios默认支持touch事件的原因吧。如果你知道底层的原因或者详细的文档说明,可以告诉我哦。

怎么解决呢

先临时把对应的touch:none,全局的写法去掉了,用了js的部分去完成或者只在控制需要的元素内进行指定这行代码。由此也总结了几个问题或者教训吧。

  • 在写全局样式的要注意影响范围
  • 在每次提交代码的时候尽可能针对不确定的部分增加备注,风险埋点,因为这次刚好是因为用户有反馈这个问题,我想到了是加了这行代码的原因,但如果是其他时候或者过了很久,其实很难定位到是因为这行代码的原因。我遇到这个问题的时候,第一感觉还是是否是脚本错误了,是否是兼容问题。如果是这样排查的话,就会浪费比较多的时间。甚至中间还找群友讨论,他们建议是否更换为绝对定位的方案,那样就真走偏了。
  • 问题拿到后的冷静分析,拿到这个问题不要过于着急,还是要分析下产生问题的原因,尤其是机型,因为我们之前做测试都是模拟器和苹果的ios,而这次报问题的都是安卓的机型,而且是小米56,坚果,华为等。联想到这些安卓机型,那么定位到可能是 :代码兼容部分的版本过低,这些不支持;代码某部分是对ios和安卓有区分解释的,和系统有关,版本无关。

更多延伸与拓展

通过touch-action可以做什么效果呢?

  • 禁止默认的滚动touch-action:none
  • 可以控制用户行为的处理细节,比如只接受x或者y方向的变化,来影响行为,确定行为边界
  • 优化用户多次点击造成界面所放
  • 更多等待你的发掘

更多

说明:如果你想更好的使用滚动相关的体验,还是入手框架吧,不然坑太多,iscroll,better-scroll(一般滚动组件依赖的库).me-scroll(个人推荐)都是不错的选择

  • 安利一篇还不错的采坑文章: 深入研究-webkit-overflow-scrolling