使用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.
然后知道原因不够,解决方案是什么?
能搜到的方案是两种,一种是通过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(),但也应该使用触摸动作来确保浏览器在调用任何事件侦听器之前知道应用程序的意图。当手势开始时,浏览器将触摸元素及其所有祖先的触摸动作值与实现手势的触摸动作值(换句话说,第一个包含滚动元素)相交。
> 这意味着在实践中,触摸动作通常只应用于具有一些自定义行为的单个元素,而不需要在该元素的任何后代上明确指定触摸动作。手势开始后,触摸动作值的更改将不会对当前手势的行为产生任何影响。
简单点说,就是这段话阐明的就是触摸事件整个的进行过程,既然它可以通过css来约定滚动的行为,那么就意味着你写了touch-action:none,就会导致原来的页面滚动失效了。这就是安卓上无法页面滚动的原因。
为什么ios没有受影响呢,我觉得可能是ios默认支持touch事件的原因吧。
怎么解决呢
先临时把对应的touch:none,全局的写法去掉了,用了js的部分去完成或者只在控制需要的元素内进行指定这行代码。由此也总结了几个问题或者教训吧。
- 在写全局样式的要注意影响范围
- 在每次提交代码的时候尽可能针对不确定的部分增加备注,风险埋点。
- 问题拿到后的冷静分析,拿到这个问题不要过于着急,还是要分析下产生问题的原因,尤其是机型。
更多延伸与拓展
通过touch-action可以做什么效果呢?
- 禁止默认的滚动touch-action:none
- 可以控制用户行为的处理细节,比如只接受x或者y方向的变化,来影响行为,确定行为边界
- 优化用户多次点击造成界面所放
如果你想更好的使用滚动相关的体验,还是入手框架吧,不然坑太多,iscroll,better-scroll(一般滚动组件依赖的库).me-scroll(个人推荐)都是不错的选择。