はじめに
JavaScriptのフレームワークやライブラリを使わずに JavaScript、HTML、そしてCSSでドロップダウンUIを実装したので、そのメモです。
ちなみにスタイル用途として、CSSフレームワークbulmaとWebアイコンのfont-awesomeを利用しています。
DropwdownのUI動作確認
実際のDropdownのUIは以下のCodepensより確認できます。
See the Pen OJyqPmJ by shinji uyama (@ushinji_0612) on CodePen.
解説
HTML
まず初めにDropwDownのHTMLの解説です。今回のDropwdownのHTMLコードは、bulmaのコード例を参考にしています。
https://versions.bulma.io/0.7.1/documentation/components/dropdown/
今回のDropdownのHTMLを簡略化すると以下の要素になります。
<!-- Dropwdown全体 --><divclass="dropdown is-active"><divclass="dropdown-trigger"><button><!-- ボタンの開閉ボタン --></button></div><divclass="dropdown-menu"id="dropdown-menu"role="menu"><!-- ドロップダウンのMenu --></div></div>DropdownのMenuの表示/非表示は <div class="dropdown">に当てられているis-activeの有無で管理します。
また、Dropdownの開閉UIは<div class="dropdown-trigger">配下のbuttonによって行います。Buttonクリックが行われた際はis-activeを追加 or is-activeを削除することで、開閉を実現しています。
CSS
次にbulmaのCSSクラスの中で、Dropdownの開閉を行うis-activeの挙動を解説します。
まず初めに開閉対象であるMenuのCSSクラス.dropdown-menuを見るとdisplay: none;が当てられています。そのため、デフォルトではブラウザ上では表示させないようにできます。
一方で、is-activeが追加することで.dropdown-menuに対してdisplay: blockを当たるため、.dropdown-menu要素が表示されます。
<!--※コードを一部省略しています-->.dropdown&.is-active.dropdown-menudisplay:block.dropdown-menudisplay:noneCSSS詳細を知りたい方は、以下のリンクよりbulmaの該当コードを確認ください。
https://github.com/jgthms/bulma/blob/9a28ea17876715d00d0a8a59b9fdabfee967e56b/sass/components/dropdown.sass#L20
JavaScript
次にDropwdownの開閉を制御するJavaScriptについての解説です。
以下のコードがDropdownを開くコードになります。
document.addEventListener('DOMContentLoaded',function(){// 1. DOMが読み込まれた際に`.dropdown-trigger`のClassを持つHTMLElementを検索varnodelist=document.querySelectorAll('.dropdown-trigger');varelements=Array.prototype.slice.call(nodelist,0);elements.forEach(function(element){// 2. Dropdownの開閉ボタンを取得と、開閉を管理するDropdownのElementを取得varbutton=element.querySelector('button');vardropdown=element.parentNode;// 3. Dropdownの開閉ボタンがクリックされた際に、`is-active`クラスを追加するイベント追加button.addEventListener('click',function(){dropdown.classList.add('is-active');});});});処理の流れとしては、DOMがマウントされた際にDropdownに関連するHTMLに対してクリックイベントを登録することで、DropdownUIを実現させています。
具体的にはDropdownのTriggerとなるButtonがクリックされた際に<div class="dropdown">に.is-activeを当てることで、DropwdownのMenuを表示させています。
次に Dropdownを閉じるUIの処理について説明します。
そもそもDropdownを閉じたいケースを考えると、以下の2つが考えられます。
1. DropdownのMenu項目がクリックされた場合
2. Dropdown以外の範囲がクリックされた場合
この場合をどうやって検知する一番簡単な方法は、TriggerであるButtonのfocusが外れた場合、つまりblurを検知すれば良いです。
具体的には以下のコードを追記すれば大丈夫です。
document.addEventListener('DOMContentLoaded',function(){varnodelist=document.querySelectorAll('.dropdown-trigger');varelements=Array.prototype.slice.call(nodelist,0);elements.forEach(function(element){varbutton=element.querySelector('button');vardropdown=element.parentNode;button.addEventListener('click',function(){dropdown.classList.add('is-active');});// 【追記】 Dropdownを閉じるコード追記+button.addEventListener('blur',function(){+dropdown.classList.remove('is-active');+});});});最後に
今回自前でDropdownの開閉UIを実装することで、すごく勉強になりました。
特に、閉じる場合のUIについて、当初は「閉じる際のクリック時の位置をDropdownのHTML範囲であるか調べて、範囲外である場合閉じる」みたいな方法を考えていました。そのため、blurを使えばシンプルに制御する方法ははとても目から鱗でした。
(補足) focusが外れた際にDropdownを閉じる実装の場合、キーボード操作ではMenuを選択する前にDropdownMenuが消えてしまいます。そのため、より良いアクセシビリティを考えると、別の方法考える必要がありますね。