簡単なJavaScriptとCSSで横並びプルダウンを自作する
Web上の入力フォームにおいて、よく使われるプルダウンのお話です。
つい先日も、「PHPで日付の表記ゆれを修正する例」で選択肢が多い場合のプルダウン※の使いづらさについて少し触れました。
※VB等のプログラミング上はドロップダウンリストとも言う
選択肢が少ない場合はラジオボタン※のほうが一覧性が高く見やすいですし、逆に数十個も選択肢がある場合もまたスクロールが長くなって使い勝手が悪いという面があります。
選択肢が少ない場合のラジオボタンとプルダウンの比較
※ラジオボタンの例
A型B型O型AB型
※プルダウンの例
文字数によっても違ってきますが、性別/血液型のように2~5個くらいの範囲であればラジオボタンで並べたほうが見やすく感じる場面も多いのではないでしょうか。
PCとスマホの両対応をしなければならない昨今、文字の折り返しなどを考えたくなくて脳死でプルダウンを実装するケースも多いとは思いますけどね。………ぼくもよくやります。
都道府県のようなデータ量の多いプルダウン
都道府県ってプルダウンで選択させられるケース多くありませんか?
表示例
あまりに多すぎて、東京は13番目、と覚えてしまったくらいです。自分の住所入力ならそれで良いんですけど、商品の発送先で選ぶ際など、47個のプルダウンから選ぶのしんどくないですか。まぁ、普通は郵便番号入力したら自動で都道府県が選択される仕組みを実装するだろうから、実運用上はあまり問題ないのかも知れません。
ちなみに、上記の例では少しでも見やすくするために地方ごとに <optgroup> で区切っています。不幸にもHTML初心者の方がこのページにたどり着いてしまった場合を考え、ソースも掲載しておきますね。
HTMLソース
<select>
<optgroup label="北海道地方">
<option>北海道</option>
</optgroup>
<optgroup label="東北地方">
<option>青森県</option>
<option>岩手県</option>
<option>宮城県</option>
<option>秋田県</option>
<option>山形県</option>
<option>福島県</option>
</optgroup>
<optgroup label="関東地方">
<option>茨城県</option>
<option>栃木県</option>
<option>群馬県</option>
<option>埼玉県</option>
<option>千葉県</option>
<option>東京都</option>
<option>神奈川県</option>
</optgroup>
<optgroup label="中部地方">
<option>山梨県</option>
<option>長野県</option>
<option>新潟県</option>
<option>富山県</option>
<option>石川県</option>
<option>福井県</option>
<option>静岡県</option>
<option>愛知県</option>
<option>岐阜県</option>
</optgroup>
<optgroup label="近畿地方">
<option>三重県</option>
<option>滋賀県</option>
<option>京都府</option>
<option>大阪府</option>
<option>兵庫県</option>
<option>奈良県</option>
<option>和歌山県</option>
</optgroup>
<optgroup label="中国地方">
<option>鳥取県</option>
<option>島根県</option>
<option>岡山県</option>
<option>広島県</option>
<option>山口県</option>
</optgroup>
<optgroup label="四国地方">
<option>香川県</option>
<option>愛媛県</option>
<option>徳島県</option>
<option>高知県</option>
</optgroup>
<optgroup label="九州地方">
<option>福岡県</option>
<option>佐賀県</option>
<option>長崎県</option>
<option>熊本県</option>
<option>大分県</option>
<option>宮崎県</option>
<option>鹿児島県</option>
<option>沖縄県</option>
</optgroup>
</select>
テキストボックスとデータリストで検索機能もどきを実装する例
表示例
↓のテキストボックスをクリックしてみてください。
マウスでクリックすると都道府県リストが表示されるため、一見プルダウンっぽいですが、これはテキストボックスです。VB/VC流に言うならコンボボックスというヤツ。
メリットとしてはインクリメンタルサーチが実装されている点。試しに上のテキストボックスに「長」と入れてみると、「長野県」「長崎県」の2つに絞り込まれるはずです。
その機能だけ聞くと使いやすそうなんですけど、日本語とインクリメンタルサーチの相性悪いんですよねー。英語だったらさ、TokyoのTを入れた瞬間に先頭がTの都道府県だけ絞り込まれて、そりゃ使いやすいでしょうよ。
でも日本語変換が必要な状況においては変換が確定した後にようやくインクリメンタルサーチが動くじゃないですか。東京の「と」を入れた瞬間に(変換する前に)絞り込まれれば使い勝手が格段に良くなると思うんですけどねー。JavaScriptをこねくりまわせば出来なくもなさそうだけど、今回は面倒なのでやりません。
その代わり(?)テキストボックスとデータリストってなんぞや?という方のためにHTMLソースを掲載しておきます。
HTMLソース
<input type="text" list="pref_list" placeholder="都道府県">
<datalist id="pref_list">
<option value="北海道"></option>
<option value="青森県"></option>
<option value="岩手県"></option>
<option value="宮城県"></option>
<option value="秋田県"></option>
<option value="山形県"></option>
<option value="福島県"></option>
<option value="茨城県"></option>
<option value="栃木県"></option>
<option value="群馬県"></option>
<option value="埼玉県"></option>
<option value="千葉県"></option>
<option value="東京都"></option>
<option value="神奈川県"></option>
<option value="山梨県"></option>
<option value="長野県"></option>
<option value="新潟県"></option>
<option value="富山県"></option>
<option value="石川県"></option>
<option value="福井県"></option>
<option value="静岡県"></option>
<option value="愛知県"></option>
<option value="岐阜県"></option>
<option value="三重県"></option>
<option value="滋賀県"></option>
<option value="京都府"></option>
<option value="大阪府"></option>
<option value="兵庫県"></option>
<option value="奈良県"></option>
<option value="和歌山県"></option>
<option value="鳥取県"></option>
<option value="島根県"></option>
<option value="岡山県"></option>
<option value="広島県"></option>
<option value="山口県"></option>
<option value="香川県"></option>
<option value="愛媛県"></option>
<option value="徳島県"></option>
<option value="高知県"></option>
<option value="福岡県"></option>
<option value="佐賀県"></option>
<option value="長崎県"></option>
<option value="熊本県"></option>
<option value="大分県"></option>
<option value="宮崎県"></option>
<option value="鹿児島県"></option>
<option value="沖縄県"></option>
</datalist>
ごく普通の <input type="text"> タグを使っているのですが、list属性でdatalistタグのIDを指定しているわけです。あとはブラウザが勝手にコンボボックス風のリストを表示してくれます。
JavaScriptで自分好みのプルダウンを実装する
というわけで、ようやく本題がこちら。あれこれ語る前に、まずは表示結果を見てみましょう。
表示例
↓のプルダウンっぽいパーツをクリックしてみてください。
都道府県- 北海道地方
- 東北地方
- 関東地方
- 中部地方
- 近畿地方
- 中国地方
- 四国地方
- 九州地方
ワイドな選択肢が開いたでしょうか?
プルダウンっぽく見えますが、実際にはCSSでそれっぽいデザインにしているだけのSPANタグです。
そのSPANタグがクリックされたときに、display:none;で隠されていたワイドな都道府県選択画面が開く、という仕組み。
HTMLとCSSとJavaScriptで構成されているので、その全てを掲載しておきますね。大したことはやってないので案外簡単ですよ。
HTMLソース
<span id="pref">都道府県</span>
<div class="select">
<ul>
<li>
北海道地方
<ul class="options">
<li>北海道</li>
</ul>
</li>
</ul>
<ul>
<li>
東北地方
<ul class="options">
<li>青森県</li>
<li>岩手県</li>
<li>宮城県</li>
<li>秋田県</li>
<li>山形県</li>
<li>福島県</li>
</ul>
</li>
</ul>
<ul>
<li>
関東地方
<ul class="options">
<li>茨城県</li>
<li>栃木県</li>
<li>群馬県</li>
<li>埼玉県</li>
<li>千葉県</li>
<li>東京都</li>
<li>神奈川県</li>
</ul>
</li>
</ul>
<ul>
<li>
中部地方
<ul class="options">
<li>山梨県</li>
<li>長野県</li>
<li>新潟県</li>
<li>富山県</li>
<li>石川県</li>
<li>福井県</li>
<li>静岡県</li>
<li>愛知県</li>
<li>岐阜県</li>
</ul>
</li>
</ul>
<ul>
<li>
近畿地方
<ul class="options">
<li>三重県</li>
<li>滋賀県</li>
<li>京都府</li>
<li>大阪府</li>
<li>兵庫県</li>
<li>奈良県</li>
<li>和歌山県</li>
</ul>
</li>
</ul>
<ul>
<li>
中国地方
<ul class="options">
<li>鳥取県</li>
<li>島根県</li>
<li>岡山県</li>
<li>広島県</li>
<li>山口県</li>
</ul>
</li>
</ul>
<ul>
<li>
四国地方
<ul class="options">
<li>香川県</li>
<li>愛媛県</li>
<li>徳島県</li>
<li>高知県</li>
</ul>
</li>
</ul>
<ul>
<li>
九州地方
<ul class="options">
<li>福岡県</li>
<li>佐賀県</li>
<li>長崎県</li>
<li>熊本県</li>
<li>大分県</li>
<li>宮崎県</li>
<li>鹿児島県</li>
<li>沖縄県</li>
</ul>
</li>
</ul>
</div>
HTML部分はさほどおかしなことをしていないと思います。
プルダウン風のデザインにする箇所はSPANタグでIDに pref を指定するだけ。
ワイドな選択画面はDIVタグで作ってあり、クラス名は select としています。
そして、実際にクリックできる項目(つまり県名)を並べるULタグのクラス名を options とします。
このIDやクラス名を使ってCSSでデザインを指定したり、JavaScriptの操作をしているので、大事なのはこの3つだけですね。
CSS部分
<style>
#pref {
border-radius:4px;
border:1px solid #666666;
cursor:pointer;
position:relative;
padding:2px 20px 2px 2px;
margin:0;
background-color:white;
font-size:0.8em;
}
#pref:after {
content:'';
position:absolute;
right:4px;
top:5px;
width:4px;
height:4px;
border:2px solid;
border-color:transparent transparent #404040 #404040;
transform: rotate(-45deg);
}
div.select {
box-shadow:4px 4px 4px 4px rgba(0, 0, 0, 0.5);
padding:0.5em 1em 1em 1em;
margin-top:4px;
display:none;
position:absolute;
background-color:white;
max-width:80%;
z-index:999;
}
div.select ul {
list-style-type:none;
padding:0;
font-size:0.9em;
}
ul.options li {
display:inline-block;
color:blue;
text-decoration:underline;
cursor:pointer;
padding-left:1em;
}
</style>
#prefは <span id="pref">都道府県</span> をプルダウン風のデザインにしている箇所ですね。角丸にしたり、マウスカーソルを手の形にしたり。………………実際のプルダウンはマウスカーソルを載せてもカーソル形状は変わらないので、そんなことする必要なかったな、と気が付いたのは完成してからです。
#pref:afterではSPANタグの後尾に下矢印を描いています。CSSで矢印や三角形を描画できることが不思議な方は下記の記事をどうぞ。
参考記事:CSSでLINE風のふきだしを出来るだけシンプルに作ってみる
div.select以降はワイドな選択画面のデザインですね。box-shadowで影を付けてウィンドウっぽくしたり、LIタグをinline-blockにすることで横並びにしたりしています。
JavaScript部分
<script>
window.addEventListener('load', function () {
document.querySelectorAll('ul.options li').forEach(elm => {
elm.onclick = function () {
document.getElementById('pref').innerHTML = elm.innerHTML;
};
});
document.getElementById('pref').onclick = function () {
event.stopPropagation();
let elm = document.querySelector('div.select');
if (elm.style.display == 'block') {
elm.style.display = '';
} else {
elm.style.display = 'block';
}
};
document.addEventListener('click', function () {
document.querySelector('div.select').style.display = 'none';
});
});
</script>
ある意味、ここが心臓部ですが、どうでしょう、思ったよりシンプルじゃありませんかね。
querySelectorのおかげで、jQueryに頼らずともシンプルな書き方ができるようになったのが大きいです。ビバ!モダンブラウザ!
やっていることをまとめるとやっぱりシンプルで、
- ページのロード完了時に、都道府県名(LIタグ)にonclickイベントを追加する。
- そのonclickイベントではid=prefのSPANタグに都道府県名を表示しているだけ。
- #prefのonclickイベントでは、選択画面が開いていたら閉じ、閉じていたら開く動作をする。
- ページ上のどこかしらがクリックされたら、選択画面は問答無用で閉じる。
これだけです。
簡単でしょう?
※但し、本家プルダウンとは違ってキーボードでの操作は想定していません。…対応が面倒だったので(小声)
まとめ
プルダウン(SELECTタグ)はデータ量が増えると使い勝手が悪いため、自前でプルダウン風の選択画面を作ってみました。
今回はわかりやすいように都道府県を例に出しましたが、実際にぼくが必要としている場面はもっと複雑なケースです。
例えば、ECサイトの商品分類などを思い浮かべて頂ければわかりやすいでしょうか。
ファッション>メンズ or レディース>トップス or ボトム or ...
家電製品>炊飯器 or 掃除機 or ...
食料品>和食 or 洋食 or ...
こういった例において、大カテゴリプルダウンで「ファッション」を選び、中カテゴリで「メンズ」を選び…………みたいなことをしているとひっじょーにイライラしてくるので、パパッとツリー形式で表示して選びたい、という需要があり、こんなプログラムを作ってみました。
少し改造すれば複数カテゴリをチェックボックスで選択したりもできますし、応用範囲も広いのではないでしょうか。
探せばjQueryプラグインあたりで高機能プルダウンみたいなものもありそうですが、それらを探したり使い方を覚えたり、はたまたバグに遭遇したり、などといったことを考えたら、サクっと自前で作ったほうが早いんじゃないかなーとぼくは思うのですよね。
尚、いつもどおり、ここに掲載したソース類はご自由にお使い頂いて構いません。
大したものではございませんが、プルダウンを自作したいと思っている方のお役に立てば幸いです。