首次合作
簡介
近三十年來,桌上型電腦的運算體驗一直以鍵盤、滑鼠或觸控板為主要使用者輸入裝置。不過,過去十年來,智慧型手機和平板電腦帶來了新的互動模式:觸控。隨著支援觸控的 Windows 8 機器問世,以及支援觸控的 Chromebook Pixel 的推出,觸控功能已成為桌面電腦的預期體驗。其中一個最大挑戰,就是打造的體驗不僅適用於觸控裝置和滑鼠裝置,也適用於使用者同時使用這兩種輸入方式的裝置!
本文將說明瀏覽器如何內建觸控功能、如何將這個全新介面機制整合至現有應用程式,以及觸控功能如何與滑鼠輸入互動。
網路平台的觸控狀態
iPhone 是第一個熱門的平台,內建專屬觸控 API,而且是網路瀏覽器中內建的服務。其他幾家瀏覽器供應商也已建立類似的 API 介面,以便與 iOS 實作相容,而這項實作目前已由 「Touch Events version 1」規格說明。觸控事件支援 Chrome 和 Firefox 桌面版、iOS 上的 Safari、Chrome 和 Android 上的 Android 瀏覽器,以及 Blackberry 瀏覽器等其他行動瀏覽器。
我的同事 Boris Smus 撰寫了一篇 HTML5Rocks 教學課程,主題是觸控事件,如果您之前沒有接觸過觸控事件,這篇教學課程仍是個不錯的入門方式。事實上,如果您從未處理觸控事件,請先閱讀該文章再繼續操作。繼續說,我會等。
完成了嗎?您現在已掌握觸控事件的基本知識,但撰寫支援觸控的互動時,會遇到以下挑戰:觸控互動與滑鼠 (以及模擬滑鼠的觸控板和軌跡球) 事件有相當大的差異。雖然觸控介面通常會模擬滑鼠,但模擬效果並非完美或完整,因此您必須同時處理這兩種互動樣式,且可能必須個別支援每種介面。
最重要的是:使用者可能會使用觸控和滑鼠
許多開發人員建立的網站會以靜態方式偵測環境是否支援觸控事件,然後假設只需要支援觸控 (而非滑鼠) 事件。這現在是錯誤的假設,只是因為有觸控事件,並不代表使用者主要使用的是觸控輸入裝置。Chromebook Pixel 和部分 Windows 8 筆記型電腦等裝置現在同時支援滑鼠和觸控輸入方式,不久後還會有更多裝置加入。在這些裝置上,使用者很自然地會同時使用滑鼠和觸控螢幕與應用程式互動,因此「支援觸控」與「不需要滑鼠支援」並不相同。您不能將問題視為「我必須編寫兩種不同的互動樣式,並在兩者之間切換」,而是要思考兩種互動如何同時運作,以及如何獨立運作。在 Chromebook Pixel 上,我經常使用觸控板,但也會伸手觸控螢幕,在同一個應用程式或網頁中,我會使用最自然的方式操作。另一方面,某些配備觸控螢幕的筆記型電腦使用者並不常使用觸控螢幕,因此不應停用或隱藏滑鼠操作。
遺憾的是,使用者的瀏覽器環境是否支援觸控輸入並不容易;理想情況下,桌上型電腦的瀏覽器一律會為觸控事件提供支援,因此隨時都能連接觸控螢幕 (例如,如果是透過 KVM 連接的觸控螢幕)。因此,您的應用程式不應該嘗試切換使用觸控和滑鼠,只要同時支援這兩種模式即可!
支援滑鼠和觸控手勢
#1 - 點按和輕觸 - 事物的「自然」順序
第一個問題是,觸控介面通常會模擬滑鼠點擊動作,因為觸控介面需要在只與滑鼠事件互動的應用程式上運作!您可以將這個工具做為捷徑使用,因為使用者透過滑鼠點選或輕觸螢幕上的「點擊」事件會持續觸發。不過,這個捷徑有幾個問題。
首先,設計進階觸控互動時必須特別小心:當使用者使用滑鼠時,系統會透過點擊事件來回應,但當使用者輕觸螢幕時,就會同時發生觸控和點擊事件。單擊事件的事件順序如下:
- touchstart
- touchmove
- touchend
- 滑鼠游標懸停
- mousemove
- mousedown
- mouseup
- click
這當然表示,如果您要處理 touchstart 等觸控事件,請務必不要同時處理對應的 mousedown 和/或 click 事件。如果您可以取消觸控事件 (在事件處理常式中呼叫 preventDefault() 即可),系統就不會為觸控產生滑鼠事件。觸控處理常式最重要的其中一項規則如下:
不過,這也會阻止其他預設瀏覽器行為 (例如捲動),雖然通常您會在處理常式中完全處理觸控事件,但您還是會想要停用預設動作。一般來說,您應該要處理及取消所有觸控事件,或是避免為該事件建立處理常式。
其次,當使用者在行動裝置上輕觸網頁中的元素時,如果網頁並未針對行動互動設計,則在觸發觸發事件和處理滑鼠事件 (mousedown) 之間,會有至少 300 毫秒的延遲。您可以使用 Chrome 執行這項操作,在 Chrome 開發人員工具中開啟「模擬觸控事件」,即可在非觸控系統上測試觸控介面!
這個延遲時間可讓瀏覽器有時間判斷使用者是否正在執行其他手勢,特別是雙擊放大/縮小手勢。很明顯地,如果您希望用手指觸碰立即回應,可能會引發問題。我們正在努力,試圖減少自動發生延遲的情況。
避免這項延遲的首要且最簡單的方法,就是「告知」行動瀏覽器您的網頁不需要縮放,這可以透過固定可視區域來實現,例如在網頁中插入以下內容:
<meta name="viewport" content="width=device-width,user-scalable=no">
當然,這並非一項萬能解決方案,因為這樣做會停用雙指縮放功能,而這項功能可能會因為無障礙性而變得必要,因此請盡量少用 (如果您真的要停用使用者縮放功能,建議您提供其他方式,以便提高應用程式中的文字可讀性)。此外,如果電腦等級裝置支援觸控功能,且行動平台上的其他瀏覽器的網頁具有無法縮放的可視區域,就不會套用這項延遲時間。
#2:觸控事件未由觸控觸發
在此要特別注意,觸控介面中模擬滑鼠事件通常不會擴充至模擬 mousemove 事件,因此如果您建立使用 mousemove 事件的漂亮滑鼠控制項,除非您特別新增 touchmove 處理常式,否則可能無法在觸控裝置上運作。
瀏覽器通常會自動為 HTML 控制項上的觸控互動實作適當的互動方式,因此,舉例來說,只有在您進行觸控互動時,HTML5 範圍控制項才有效。不過,如果您已實作自己的控制項,這些控制項可能無法在點選和拖曳類型的互動上運作;事實上,某些常用的程式庫 (例如 jQueryUI) 尚未原生支援這種方式的觸控互動 (不過,jQueryUI 有幾個猴子修補程式可修正這個問題)。這是我在升級 Web Audio Playground 應用程式以使用觸控功能時遇到的一個問題之一,這些滑桿是以 jQueryUI 為基礎,所以無法與點選及拖曳的互動方式操作。我變更了成 HTML5 範圍控制項,而且可以正常運作。當然,我也可以直接新增 touchmove 處理常式來更新滑桿,但這樣做有一個問題…
#3:Touchmove 和 MouseMove 並非相同
我發現有幾位開發人員遇到一個陷阱,那就是觸控移動和滑鼠移動處理常式呼叫到相同程式碼路徑。這些事件的行為非常相似,但仍有細微差異,特別是觸控事件一律會指定觸控動作開始時的元素,而滑鼠事件則會指定滑鼠游標目前所在的元素。因此,我們有 mouseover 和 mouseout 事件,但沒有對應的 touchover 和 touchout 事件,只有 touchend。
使用者最常碰到的元素是否移除 (或重新放置) 時,最容易遇到這種情況。舉例來說,假設圖片輪轉介面在整個輪轉介面上有觸控處理常式,可支援自訂捲動行為。可用圖片變更時,您可以移除部分 <img>
元素並新增更多元素。如果使用者開始輕觸其中一張圖片,而您又將該圖片移除,則您的處理常式 (位於 img 元素的祖系上) 就會停止接收觸控事件 (因為他們被分派到樹狀結構中不存在的目標位置),看起來就像使用者把手指手放在某處,即使他們可能已移動而最終將其移除。
當然,您也可以避免在觸控功能啟用時移除具有 (或具有具有) 觸控處理常式的元素,以免發生這個問題。另外,最佳做法是不要註冊靜態 touchend/touchmove 處理常式,而是等到觸控開始事件後,再將 touchmove/touchend/touchcancel 處理常式新增至 touchstart 事件的 target (並在結束/取消時移除)。這樣一來,即使目標元素已移動/移除,您仍可繼續接收觸控事件。您可以在這裡稍微玩玩這個功能 - 輕觸紅色方塊,並在按住 Escape 鍵的同時將其從 DOM 中移除。
#4:觸控和懸停
滑鼠游標隱喻可將游標位置與主動選取分開,讓開發人員使用懸停狀態隱藏或顯示可能與使用者相關的資訊。不過,目前大多數的觸控介面都不會偵測手指是否在目標上「懸停」,因此除非您也提供觸控友善的方式來存取這項資訊,否則請勿根據懸停提供重要語意資訊 (例如提供「這項控制項是什麼?」彈出式視窗)。您必須謹慎使用懸停功能,以便向使用者傳達資訊。
不過有趣的是,在某些情況下,CSS :hover 擬類別可由觸控介面觸發,輕觸元素會在手指按下時使其處於 :active 狀態,並且取得 :hover 狀態。(在 Internet Explorer 中,:hover 只會在使用者手指按下時生效,其他瀏覽器則會在下次輕觸或滑鼠移動時,讓 :hover 生效)。如要在觸控介面上顯示彈出式選單,這是個不錯的做法,讓元素設為啟用後會產生 :over 狀態。例如:
<style>
img ~ .content {
display:none;
}
img:hover ~ .content {
display:block;
}
</style>
<img src="/awesome.png">
<div class="content">This is an awesome picture of me</div>
一旦輕觸其他元素,就不再啟用,而懸停狀態會消失,就像使用者使用滑鼠指標並將其移出元素一樣。您可能會想將內容包裝在 <a>
元素中,以便將其設為 Tab 停靠點。這樣一來,使用者只要將滑鼠游標懸停或點選、輕觸或按下按鍵,即可切換額外資訊,而不需要 JavaScript。當我開始著手讓 Web Audio Playground 與觸控介面搭配運作時,我發現彈出式選單在觸控時運作良好,這讓我感到驚喜,因為我使用了這種結構!
上述方法適用於以滑鼠指標為基礎的介面,以及觸控介面。這與在滑鼠游標上方使用「title」屬性不同,後者在元素啟用時不會顯示:
<img src="/awesome.png" title="this doesn't show up in touch">
#5:觸控與滑鼠精確度
雖然滑鼠與實際情況不符,但實際上它們非常精確,因為基礎作業系統通常會追蹤游標的確切像素精確度。另一方面,行動裝置開發人員發現,手指觸碰觸控螢幕的準確度不高,主要是因為手指與螢幕接觸時的表面積大小 (以及手指遮住螢幕的部分)。
許多個人和公司已針對如何設計可支援手指互動的應用程式和網站進行廣泛的使用者研究,並且有許多書籍討論這個主題。基本建議是增加邊框間距,以便增加觸控目標的大小,並增加元素間的邊距,以降低誤觸的機率。(邊距不會納入觸控和點擊事件的命中偵測處理,但邊框會納入)。我必須對 Web Audio Playground 進行的主要修正之一,就是增加連接點的大小,讓使用者更容易精準地觸碰。
許多處理以觸控為基礎的介面瀏覽器供應商也已在瀏覽器中導入邏輯,以便在使用者觸碰螢幕時鎖定正確的元素,並降低點按錯誤的可能性。不過,這項功能通常只會修正點擊事件,而非移動事件 (雖然 Internet Explorer 似乎也會修改 mousedown/mousemove/mouseup 事件)。
#6:請將觸控事件處理常式控制在範圍內,否則會影響捲動速度
請務必將觸控處理常式限制在您需要的元素中;觸控元素的頻寬可能非常高,因此請避免在捲動元素上使用觸控處理常式 (因為您的處理作業可能會干擾瀏覽器的最佳化作業,導致觸控捲動速度緩慢且不流暢 - 新式瀏覽器會嘗試在 GPU 執行緒上捲動,但如果必須先透過 JavaScript 檢查每個觸控事件是否會由應用程式處理,就無法執行此操作)。您可以查看這項行為的示例。
如要避免發生這個問題,請遵循以下指引:如果您只處理 UI 的一小部分觸控事件,請只在該部分附加觸控處理常式 (例如,不要在網頁的 <body>
上附加);簡而言之,請盡可能限制觸控處理常式的範圍。
#7:多點觸控
最後一項有趣的挑戰是,雖然我們稱之為「觸控」使用者介面,但幾乎普遍都支援多點觸控功能,也就是說,API 一次會提供多個觸控輸入。開始在應用程式中支援觸控功能時,請考量多點觸控可能對應用程式造成的影響。
如果您主要以滑鼠操作建構應用程式,那麼您習慣最多使用一個游標點來建構應用程式,因為系統通常不支援多個滑鼠游標。對許多應用程式來說,您只需將觸控事件對應至單一遊標介面,但大多數適用於電腦版觸控輸入的硬體都可以處理至少 2 項同時輸入,而且大多數新硬體似乎都支援至少同時輸入 5 項輸入。開發螢幕鋼琴鍵盤時,您當然會想支援多個同時觸控輸入。
目前實作的 W3C Touch API 沒有 API 可判斷硬體支援的接觸點數量,因此您必須盡可能採用最佳估算值,決定使用者需要多少接觸點。當然,也請特別留意您在實務和調整方面看到多少接觸點。舉例來說,如果在鋼琴應用程式中,您從未看到超過兩個觸控點,建議您新增一些「和弦」UI。PointerEvents API 確實提供可判斷裝置功能的 API。
修飾
希望本文針對使用觸控與滑鼠互動時可能會遇到的常見挑戰提供一些指引。當然,比起其他建議,您更需要在行動裝置、平板電腦和結合滑鼠和觸控功能的電腦環境中測試應用程式。如果您沒有觸控 + 滑鼠硬體,請使用 Chrome 的「模擬觸控事件」功能,測試不同的情境。
您可以按照這些指引,輕鬆建構出能與觸控輸入、滑鼠輸入,甚至是同時使用這兩種互動方式的互動式體驗。