css:touch-action導致安卓無法滾動頁面

RobinsonZhang發表於2018-10-22

前言

相信大家搜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(個人推薦)都是不錯的選擇

相關文章