JavaScriptでのイベント発生タイミング(クリック、右クリック時)

JavaScriptでクリックなどのイベントを取得できますが、その発生(発火)タイミングは実装方法によってまちまちです。同じブラウザでもOSが違えば順番などが違ってきます。特に右クリック時(ここでは利便上そう呼びます)などに違いが出てきます。
今回は、documentに対して、動作を行ったときの、イベントの発生の順番を調べてみました。

MacOS共通(大半のブラウザで同じ)

クリック

押す
mousedown
離す
mouseup
click

(押下中に移動した場合の)クリック

押す
mousedown
移動
mousemove
離す
mouseup
click

ダブルクリック

押す
mousedown
離す
mouseup
click
押す
mousedown
離す
mouseup
click
dblclick

(押下中に移動した場合の)ダブルクリック

押す
mousedown
離す
mouseup
click
押す
mousedown
移動
mousemove
離す
mouseup
click
dblclick

MacOS(10.10.5) Chrome(46.0.2490.80)

右クリック

押す
mousedown
contextmenu(mousedownのタイミングで発生)
離す

(押下中に移動した場合の)右クリック

押す
mousedown
contextmenu
移動
離す
mousemove(mouseupのタイミングで発生)

MacOS(10.10.5) Firefox(42.0)

右クリック

押す
mousedown
contextmenu(mousedownのタイミングで発生)
離す
mouseup
click(clickイベントが発生。ただし、処理が重いと発生しない)

(押下中に移動した場合の)右クリック

押す
mousedown
contextmenu
移動
mousemove
離す
mouseup
click(clickイベントが発生。ただし、処理が重いと発生しない)

MacOS(10.10.5) Safari(8.0.8)

右クリック

押す
mousedown
contextmenu(mousedownのタイミングで発生)
離す

(押下中に移動した場合の)右クリック

押す
mousedown
contextmenu
移動(mousemoveイベントが発生しない)
離す

MacOS(10.10.5) Opera(33.0.1990.58)

右クリック

押す
mousedown
contextmenu(mousedownのタイミングで発生)
離す

(押下中に移動した場合の)右クリック

押す
mousedown
contextmenu
移動
離す
mousemove(mouseupのタイミングで発生)

Windows(8.1 Enterprise) Firefox(42.0)

右クリック

押す
mousedown
離す
mouseup
click
contextmenu

(押下中に移動した場合の)右クリック

押す
mousedown
移動
mousemove
離す
mouseup
click
contextmenu

Windows(8.1 Enterprise) Internet Explorer(11.0.9600.18053)

右クリック

押す
mousedown
離す
mouseup
contextmenu

(押下中に移動した場合の)右クリック

押す
mousedown
移動
mousemove
離す
mouseup
contextmenu

Windows(8.1 Enterprise) Chrome(46.0.2490.80 m)

右クリック

押す
mousedown
離す
mouseup
contextmenu
mousemove(なぜか発生。クリック時も同様)

(押下中に移動した場合の)右クリック

押す
mousedown
移動
mousemove
離す
mouseup
contextmenu
mousemove(なぜか発生。クリック時も同様)

まとめ

イベントの発生タイミングは処理系によってまちまちだということを念頭に置いておくとよいでしょう。

特に、MacのFirefoxの右クリック時は、contextmenuイベントのすぐ後にclickイベントが発生します。ただし、このclickイベントに関しては、処理が重くなると発生しないようです。
なぜ、重くなると発生しないかはわかりません。

解決策としては、
http://d.hatena.ne.jp/rikuba/20101221/1292875401
を参考にするとわかりやすいです。
JavaScriptやjQueryで「document」でイベントリスナーを登録するのではなく、「document.body」にしてあげることで解決します。もちろんその場合は、documentではないので、要素がない部分をクリックしてもなにも起こらないですが。