CSS touch-action簡介與treated as passive錯誤解決

一、mousemove報treated as passive錯誤

其實這個問題出現有一段時間了,主要麻煩的是,以前沒有,後來,Chrome和Safari瀏覽器升級了,然後出現這個錯誤,而且就在一個月前,Chrome瀏覽器還只是黃色的警告,現在直接就紅色錯誤獻上。

例如,隨便新建一個空白頁面,寫上如下JavaScript代碼:

document.addEventListener('touchmove', function (event) {
    event.preventDefault();
});

然後在移動端模式下頁面上點擊滑來滑去記下,就可以看到一大堆錯誤:

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

紅燦燦的報錯截圖如下:

treated as passive報錯

這是因爲Chrome及其內核瀏覽器更新了一項新特性,具體見(打開看人品):https://www.chromestatus.com/features/5093566007214080

如果僅僅是錯誤,不影響功能其實還好,但是,這個報錯會影響我們之前運行很OK的交互操作,例如,自定義滾動,或者元素拖拽效果等,會觸發瀏覽器原生的滾動,產生不好的交互體驗效果。

如何解決這個問題呢?

我所知道的有兩個方法。

二、方法一:touch-action:none解決passive錯誤

加入如下CSS:

html {
    touch-action: none;
}

報錯就會無影無蹤。

touch-action是移動端一個與手勢觸摸密切相關的CSS屬性,原本源自windows phone手機,微軟系,後來被Chrome吸收借鑑,Firefox瀏覽器跟上,然後Safari也部分支持,目前已經可以說是在移動端可以暢行的CSS屬性。

支持的關鍵字值有:

touch-action: auto;
touch-action: none;
touch-action: pan-x;
touch-action: pan-left;
touch-action: pan-right;
touch-action: pan-y;
touch-action: pan-up;
touch-action: pan-down;
touch-action: pinch-zoom;
touch-action: manipulation;

其中:

  • auto是默認值,表示手勢操作什麼的完全有瀏覽器自己決定(如<meta>元素的viewport設置)。
  • manipulation表示瀏覽器只允許進行滾動和持續縮放操作,類似雙擊縮放這種非標準操作就不可以。想當初,click事件在移動端有個300ms延時,就是因爲避免和手機雙擊行爲發生衝突。然而,當我們設置了touch-action:manipulation幹掉了雙擊行爲,則顯然,300ms延時就不復存在,因此,下面的CSS聲明可以用來避免瀏覽器300ms延時問題。
    html {
        touch-action: manipulation;
    }

上面2個關鍵字屬性值(automanipulation)是Safari唯一支持的兩個touch-action屬性值,iOS Safari就是爲用戶操碎了心,就怕開發者把一些對用戶無障礙訪問有幫助的東西去掉,例如不支持touch-action:none以及iOS10+中設置viewportuser-scalable=no已經無法阻止用戶手指縮放屏幕了,或許在Safari看來,對於一個網頁,沒有任何理由阻止用戶放大看你的網頁內容。

至於其他關鍵字,正如字面意思,要麼只能左移,要麼只能左右移動,要麼只能右移之類,具體如下:

  • none表示不進行任何touch相關默認行爲,例如,你想用手指滾動網頁就不行,雙擊放大縮小頁面也不可以,所有這些行爲要自定義。
  • pan-x表示手指頭可以水平移來移去。
  • pan-left表示手指頭可以往左移動,移動開始後還是可以往右恢復的。
  • pan-right表示手指頭可以可以往右移動,移動開始後還是可以往左恢復的。
  • pan-y表示手指頭可以垂直移來移去。
  • pan-up表示手指頭可以往上移,移動開始後還是可以往下恢復的。
  • pan-down表示手指頭可以往下移,移動開始後還是可以往上恢復的。
  • pan-zoom表示手指頭可以用來縮放頁面。

上述部分關鍵字可以組合使用,分pan-y, pan-up, pan-downpan-x, pan-left, pan-right以及pan-zoom這三組,然後這三組關鍵字可以任意組合,例如:

.example {
    touch-action: pan-left pan-up pan-zoom;
}

表示可以左移,上移和縮放。

此方法不足
1. iOS Safari瀏覽器不支持;
2. 幹掉了可能需要的原生的touch相關行爲。

不過主要問題還是iOS Safari瀏覽器不支持,第2點不足我們可以當我們需要阻止時候JS設置touch-actionnone,不需要在JS還原即可,不是大問題。

iOS Safari對於傳統移動網頁可以重要瀏覽器,不可忽略,怎麼辦,有沒有什麼其他方法呢?有!就是下面這個。

三、方法二:passive:false解決passive錯誤

問題代碼是:

document.addEventListener('touchmove', function (event) {
    event.preventDefault();
});

修復後的JavaScript代碼是:

document.addEventListener('touchmove', function (event) {
    event.preventDefault();
}, {
    passive: false
});

也就是addEventListener的第三個參數傳遞passive:false,告訴瀏覽器,我這個事件就是不是消極的,是老子主動要這麼做的。瀏覽器此時也不好說什麼,然後,我們以前出問題的代碼就能正常運行了。

如果是Zepto.js語法下的事件呢,例如:

$(document).on('touchmove', function (event) {
    event.preventDefault();
});

根據我查看Zepto的源碼分析,目前並不支持,請使用原生的addEventListener代替。

四、結束語

意外學到了CSS touch-action相關的一些知識。有了touch-action:manipulation,我們可以在網頁中放心大膽使用click事件了,至於自定義的touch事件之流可以退出歷史舞臺了,哦也!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章