bootstrapのdropdownを自動開閉
Bootstrap3 の dropdown menu をマウスオーバーで自動開閉したい†
http://dora.bk.tsukuba.ac.jp/event/ICSPM24/index
これのメニューの所で、クリックしなくてもメニューが開くようにしたかったのです。
よく知られた方法もあるようなのですが・・・†
例えばこちらで紹介されていました。
css に以下を追加するだけで、ほぼ望み通りの動作をします。
LANG:css @media only screen and (min-width : 768px) { /* デスクトップ表示ではホバー操作でドロップダウンを表示 */ .dropdown:hover .dropdown-menu { display: block; } }
同じページでは、親要素のクリックでリンク先に飛ぶためのハックも記載されています。 ただ、それを追加してしまうとタッチデバイスでドロップダウンを開けなくなってしまうため、 モバイルファーストで開発するなら親要素にリンクを張るのはやめた方が良いと思います。
上記コードで気になる点†
試したところ、いくつか難点がありそうです。
- モバイルデバイスで親要素をタップしてメニューを開いた後、 もう一度親要素をタップしてもメニューが閉じない
- マウスオーバーでメニューが開いた際に親要素がハイライトされない
2. はまだしも、 1. は期待する動作と異なるため、ユーザーが戸惑うのではないかと思います。
以下のコードは車輪の再発明っぽくはありますが、 タップデバイスの動作が変化していないところに、 少しだけメリットがあると思います。
下記コードで気になる点†
一方、下記のコードでは親要素をマウスクリックするといろいろおかしなことが起きます。
- Firefox, IE では親要素をクリックすればメニューが閉じますが、Chrome では2回クリックしないと閉じません
- クリックでメニューを閉じると、親要素のハイライトが残ってしまいます
今のところマウスオーバーで開いたメニューをマウスクリックで閉じなくてもいいでしょ、 ということで、目をつぶっています。。。
基本を確認†
ドロップダウンの開閉を行うコードはこの部分です。
https://github.com/twbs/bootstrap/blob/master/js/dropdown.js
open というクラスを追加すれば良いことが分かります。
とりあえず開く†
hover で open を追加するコードを書きました。
ただこれだと2つ問題があって、
- タッチデバイスではメニューが開かない
- 画面幅が狭くなって collapse したメニューでもマウスオーバーで開いてしまう
タッチデバイスへの対応†
そもそもスマホなどのタッチデバイスではマウスオーバーが無いので自動開閉はしなくて良いのですが、 上のコードだと親要素をタップでもメニューが開かなくなってしまいます。
というか、1回目は開かず、2回目で開きます。
これは、タッチデバイスでの画面タップでは
- mouseover が発生 -> open
- mouseclick が発生 -> toggle すなわち close
が連続して起きるためです。
これを回避するために次のようにしました。
mouseover ではなく 「mousemove の2回目」 でメニューを開きます。
タップでは mouseclick 前に mousemove が1回しか起きないので、 これで正しくメニューを開けます。
マウスカーソルの移動では mousemove の1回目で開いても2回目で開いても体感的には遅れは感じられません。
collapse では開かないようにする†
非 collapse 状態では li.dropdown が float:left なので、 それを利用すればいいように思いました。
LANG:javascript if ( $this.css('float')!='left' ) return;
を1行加えました。
最終版†
次のコードで動いているようです。