■■■ やり方 ■■■
ブラウザが自動で設置するセレクトボックスは、
自由にカスタマイズできないから、
自動で設置されたセレクトボックスを「display:none」で非表示にし、
セレクトボックスの代わりの UI を <div> などで設置して、
その UI でセレクトボックスの選択値を操作すればいい。
セレクトボックスの代わりになる UI で、
オプションを入れるボックスの max-height を、
line-height × 10 にすればいいだけ。
■■■ サンプル ■■■
即席で作成したサンプル。
下記の <scritp> 内の Javascript コードを、
そのまま JS ファイルとして保存すれば、
その JS ファイルをページに読込んで
<select> に data-customselect 属性を付けるだけで動作する
JS プラグインとしても使いまわせる。
────────────────
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ページタイトル</title>
<!---- カスタムセレクトボックス ---->
<script>
/*---- ルートオブジェクト ----*/
var customselect = new Object();
/*---- スタイルシート|オブジェクト ----*/
customselect.stylesheet =
document.querySelector( "head" ).
appendChild( document.createElement( "style" ) ).sheet;
/*---- スタイルシート|関数 ----*/
customselect.css = function( selector, style ){
this.insertRule(
( Array.isArray( selector ) ? selector.join( ", " ) : selector )+"{"+
( Array.isArray( style ) ? style.join( "; " ) : style )+"}",
this.cssRules.length );
}.bind( customselect.stylesheet );
/*---- スタイルシート|設定 ----*/
customselect.css( ".customselect", [
"position: relative",
"display: inline-block",
"line-height: 24px; white-space: nowrap",
"padding: 0px 0px 0px 8px",
"margin: 0px 4px",
"border: solid 1px #666",
"border-radius: 3px",
"background: #fff",
"color: #666",
"font-size: 16px",
"text-align: left",
"cursor: pointer"
] );
customselect.css( ".customselect::after", [
"content: ''",
"position: relative; z-index: 0",
"display: inline-block",
"width: 24px",
"height: 24px",
"margin-left: 16px",
"border-radius: 0px 3px 3px 0px",
"background: #ccc",
"vertical-align: bottom"
] );
customselect.css( ".customselect::before", [
"content: ''",
"position: absolute; top: 9px; right: 7px; z-index: 10",
"display: block",
"width: 0px",
"height: 0px",
"border-style: solid",
"border-width: 6px 5px 0px 5px",
"border-color: #333 transparent"
] );
customselect.css( ".customselect > div", [
"position: absolute; left: 0px; top: 25px; z-index: 100",
"display: none",
"width: 100%",
"line-height: 20px; min-height: 20px; max-height: 200px",
"padding: 2px",
"margin: 0px",
"border: solid 1px #666",
"overflow: auto"
] );
customselect.css( ".customselect.open > div", "display: block" );
customselect.css( ".customselect > div > a", [
"display: block",
"padding: 0px 8px",
"margin: 0px",
"background: #fff",
"color: #666",
"text-decoration: none"
] );
customselect.css( ".customselect > div > a:hover", "background: #eee" );
customselect.css( "[ data-customselect ]", "display: none" );
/*---- 初期化 ----*/
customselect.init = function(){
//----] 取得
customselect.select = document.querySelectorAll( "[ data-customselect ]" );
//----] 設置
customselect.box = new Array();
Array.prototype.forEach.call( customselect.select, function( select, selectIndex ){
// ボックス
var next = select.nextSibling;
var box = select.parentNode.insertBefore( document.createElement( "div" ), next );
box.classList.add( "customselect" );
box.onclick = function(){ customselect.closeAll( selectIndex ); this.classList.toggle( "open" ) };
// 値
var span = box.appendChild( document.createElement( "span" ) );
span.textContent = select.value;
// オプション
var options = box.appendChild( document.createElement( "div" ) );
Array.prototype.forEach.call( select.options, function( option, optionIndex ){
var anchor = options.appendChild( document.createElement( "a" ) );
anchor.textContent = option.text;
anchor.setAttribute( "href", "javascript:customselect.set( "+selectIndex+", "+optionIndex+" )" );
} );
// リストに追加
customselect.box.push( box );
} );
//----] セレクトボックス以外をクリックして閉じる
document.addEventListener( "click", function( evt ){
if( evt.target.querySelector( ".customselect" ) ){ customselect.closeAll() }
}, false );
};
/*---- 選択 ----*/
customselect.set = function( select, option ){
customselect.select[ select ].selectedIndex = option;
customselect.box[ select ].querySelector( "span" ).textContent =
customselect.select[ select ].value;
customselect.box[ select ].classList.remove( "open" );
}
/*---- すべて閉じる ----*/
customselect.closeAll = function( exception ){
Array.prototype.forEach.call( customselect.box, function( box, index ){
if( index===exception ){ return }
box.classList.remove( "open" );
} );
};
/*---- 実装 ----*/
window.addEventListener( "DOMContentLoaded", customselect.init, false );
</script>
</head>
<body>
<form name="fromTest" method="get" action="#">
<select name="select1" data-customselect>
<option value="a">A</option>
<option value="b">B</option>
<option value="c">C</option>
<option value="d">D</option>
<option value="e">E</option>
<option value="f">F</option>
<option value="g">G</option>
<option value="h">H</option>
<option value="i">I</option>
<option value="j">J</option>
<option value="k">K</option>
<option value="l">L</option>
<option value="m">M</option>
<option value="n">N</option>
</select>
<select name="select2" data-customselect>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<input type="submit" value="決定">
</form>
</body>
</html>
────────────────
■■■ スクリプトの説明 ■■■
上記のサンプルでは、
<head> 内の <script> において、
ページ内のセレクトボックスをカスタマイズする Javascript を記述。
<body> 内では、
<select> 要素に data-customselect 属性を付けるだけで、
カスタマイズされたセレクトボックスに表示が変わる。
以下、スクリプトについて説明
【1】ルートオブジェクト
まず、
セレクトボックスのカスタマイズに使う Javascript の変数を
プロパティとして囲い込むためのオブジェクト customselect を用意。
────────────────
var customselect = new Object();
────────────────
この機能の実装に使う変数は、
すべてこのオブジェクト customselect のプロパティとして用意する。
【2】スタイルシート操作
Javascript だけでこの機能を実装できるように、
CSS の設定も Javascript で行う。
そのために、まずこの機能専用の StyleSheet オブジェクトを用意する。
────────────────
customselect.stylesheet =
document.querySelector( "head" ).
appendChild( document.createElement( "style" ) ).sheet;
────────────────
<head> 内に動的に <style> タグを挿入し、
その sheet プロパティを StyleSheet オブジェクトとして取得している。
この StyleSheet オブジェクトに対して、
insertRule() メソッドを実行することで
<style> に必要な CSS の指定を追加していく。
CSS の追加がしやすいように、
CSS セレクタとスタイルを引数として渡すことで、
insertRule() を実行する関数 customselect.css() をつくっておく。
────────────────
customselect.css = function( selector, style ){
this.insertRule(
( Array.isArray( selector ) ? selector.join( ", " ) : selector )+"{"+
( Array.isArray( style ) ? style.join( "; " ) : style )+"}",
this.cssRules.length );
}.bind( customselect.stylesheet );
────────────────
セレクタやスタイル指定の文字列が長い場合、
[ "~", "~", … ] のように配列で分割して渡せるように、
Array.isArray() で引数が配列かどうかを調べ、
それによって引数の適用方法を分岐させている。