ENTER or SPACE, KEYDOWN or KEYUP

前一篇文章作動行為 Activation Behavior 發佈之後,卡西又做了一些測試,發現到 ENTERSPACE 的觸發時機其實不一樣:

然後我仔細測試過發現真的是這樣,而且 SPACEkeypress的狀態,就像是滑鼠按鍵按下去但是還沒放開時的樣子,然後這又讓我有點好奇起來了,仔細搜尋一番,發現 web 標準都沒有提到這個細節的定義,唯一有一點關係的是卡西也有找到的 WAI-ARIA Authoring Practices Issue 610,於是我就覺得這應該和 Web 標準定義沒關係,應該是更古老的預設行為,於是改變方向改找 Windows 預設行為相關的文件,搜尋一陣子其實也找不太到東西,大概是因為 GUI 和 Windows 剛出的時候其實 www 還不知道在哪裡吧,不過後來還是找到兩篇 stackoverflow 的問答看起來是相關的:

總和這兩篇的內容,大概整理一下:

這個行為應該是 Windows 一開始的時候就如此設計的了(看起來是很難找到相關設計的文件),然後實際上和 ENTER 相關(相對)的操作其實是 ESC 鍵,ENTER 鍵代表的是直接點 default button(例如 form 的 submit、dialog 的 ok 之類的),或是可以說是執行元件預設的行為,至於 ESC 鍵則是取消,不過取消在網頁的控制元件中幾乎是不存在的,過去有的大概只有<select>展開下拉選單後又決定不選時可以取消,到 HTML5 則又多了<dialog>有取消的行為(關閉 dialog),大概也是因為這個原因讓人忽略了 ENTERESC 的關係,變成注意到 ENTERSPACE 都可以操作元件;至於 SPACE 鍵其實就像是滑鼠點擊,keyDown如同mouseDownkeyUp如同mouseUp,要到keyUp才算一個點擊的動作,也就是到這時候才會去觸發click事件。

搞清楚這現象的原理之後,其實也就更容易理解 WAI-ARIA Authoring Practices 的範例那些 ENTERESCSPACE 幾個按鍵行為為什麼是那樣了,當然,以後需要客製 widget 時也不用再對這幾個按鍵的行為該怎樣定義苦惱了。


作動行為 Activation Behavior

前幾天全知全能的米奧大人在 Twitter 上徵求中階的 JavaScript 課程:

然後 Jedi 提供了一個題目:

後來米奧大人真的交作業了,也有提出一些問題,然後卡西有回應:

其中,「keyup 該觸發 button 上的 onclick」這句引起了我的興趣。

為了要顧及到網頁親和力,所有的控制元件的操作都應該要可以用鍵盤執行,所以像是 button 的動作也應該要可以用鍵盤控制,但是其實我以前一直搞不清楚,這之間正確的關係應該是怎樣,就三種可能性:

  • key 事件觸發 click 事件,click 事件有 default handler
  • click 事件觸發 key 事件,key 事件有 default handler
  • click 事件和 key 事件都有同一個 default handler

當我看到卡西那段文字的時候,我覺得他應該說的是有憑據的,不過我也覺得有些不正確,像是就我的認知,button 的 key 事件預設是不會觸發 click 事件的,於是我就花了點時間研究一下網路標準,這次終於找到規範和正確的關係了。

我先從 button 標籤開始查起,然後注意到一段,在說明 button 的 activation behavior 行為應該如何的文字,行為分成 submit button、reset button 和 button 三種,其中前兩個就像是在說 submit button 和 reset button 的行為一樣,所以我就了解到,activation behavior 就是我要找的關鍵字了,目前將它翻譯為「作動行為」。

然後在 HTML 6.3 Activation 找到:

Certain elements in HTML have an activation behavior, which means that the user can activate them. This is always caused by aclickevent.

The user agent should allow the user to manually trigger elements that have an activation behavior, for instance using keyboard or voice input, or through mouse clicks. When the user triggers an element with a defined activation behavior in a manner other than clicking it, the default action of the interaction event must be to fire aclickevent at the element.

第一段就是說作動行為(activation behavior)都是click事件觸發,第二段則是說瀏覽器要讓其它方法(像是鍵盤、語音操作等)可以觸發作動行為的話,實做的方法應該是在該事件的處理器(event handler)內觸發click事件來觸發該 HTML 元素的作動行為。這段文字就可以證明卡西說的基本上沒錯,另外就是我有疑惑的,應該是keydown還是keyup事件呢?根據我自己的實驗結果應該是要用keydown,不過總還是想找一下標準定義的出處,雖然沒有找到很明確的文字說明,不過 UI Events 3.5. Activation triggers and behavior 裡面的 EXAMPLE 4 內確實是寫 keydown event,當然keydown的時間點也比較符合期待,目前在不同標準文件內看到的範例也都是用 keydown。

查到這邊大概就可以確定,正確的關係應該是「key 事件觸發 click 事件,click 事件有 default handler」,不過卡西說的小錯誤是應該要用 keydown 事件,然後我在 twitter 有回說普通 button 不應該 keydown 觸發 click 則是我當時的錯誤認知(請見 ENTER or SPACE, KEYDOWN or KEYUP)。

再來,其實我還很好奇,哪裡有定義不同的元素分別用哪些按鍵 active 呢?因為表單送出是用 ENTER 鍵,但是像是 checkbox 的狀態切換卻是用 SPACE 鍵;上面提供的幾份文件也都沒講到這部分的定義,有種刻意避開的感覺,後來又找了許久才終於找到,其實是放在 WAI-ARIA Authoring Practices 這份 Working Group Note 內,拿 checkbox 為例,在它的 Keyboard Interaction 段落內就明白寫了:

When the checkbox has focus, pressing the Space key changes the state of the checkbox.

當然也有 button 的規範,就是同時有定義spaceenter;由於這份文件是 Working Group Note,規範的硬性比較低,這應該也是故意為之的。

最後來整理一下,首先是 HTML 文件有定義,預設的作動行為都是透過click事件觸發,但是同時也要保留其它操作介面觸發作動行為的可能性,像是常見的鍵盤行為,而其它操作方式都要透過觸發click事件的方式來觸發作動行為;再來就是不同 HTML 元素的作動行為要做哪些事情也是在 HTML 文件內;至於不同 HTML 元素要支援哪些按鍵呢,這部分就要交叉參考 ARIA in HTMLWAI-ARIA Authoring Practices 兩份文件了,前者用來查詢 HTML 元素對應的 ARIA role,後者可以根據 role 來判斷要支援哪些鍵盤按鍵。

以後要做自訂的控制元件的時候,就可以正大光明的把主要的動作寫在 onclick 事件下了(然後根據情況去加上 key event)。


更之前的文章