CSSのappearanceを使ったセレクトボックスのカスタマイズ

セレクトボックス(select要素)のデザインを、CSSのappearanceを使ってカスタマイズする方法のまとめです。
つい先日、セレクトボックスをカスタマイズする機会があり、調べてみましたのでメモ代わりにまとめておきます。思いのほか、モダンブラウザでは見た目を整えることができるようなので機会があれば試してみてはいかがでしょうか。
HTML
HTMLは通常通り組めばOKです。
1 2 3 4 5 6 7 8 9 10 |
<div class="select-box01"> <select> <option value="">セレクトボックス01</option> <option value="">選択肢01</option> <option value="">選択肢02</option> <option value="">選択肢03</option> <option value="">選択肢04</option> <option value="">選択肢05</option> </select> </div> |
CSS
セレクトボックスそのままではほとんどスタイルを適用することはできません。
まずはデフォルトのスタイルを無効にする必要があります。
1 2 3 4 5 |
.select-box01 select { -webkit-appearance: none; -moz-appearance: none; appearance: none; } |
これを適用すると、以下のような外観になります。元のスタイルがなくなり、右端の矢印も消えてなくなります。今のところ、ChromeやFirefoxでもappearanceはベンダープレフィックス(-webkit-や-moz-など)が必要です。

(キャプチャは Mac版Chrome)
なお、自動的に最新バージョンを使うことになるのであまり気にすることはないと思いますが、Firefox30〜34では「-moz-appearance: none;」が機能しないというバグがあったようです。
詳しくは、GitHub「How to hide <select> dropdown's arrow in Firefox when using "-moz-appearance: none;".」で書かれています。この不具合はバージョン35で修正されたということで、35、36で確認したところ問題ありませんでした。
あとはボーターの色を変えたり高さを調節したりと、結構自由にスタイリングが可能です。
試しに、グラデーションと矢印の背景画像を敷いたりして見た目を整えてみます。
1 2 3 4 5 6 7 8 9 10 11 12 |
.select-box01 select { width: 100%; padding: 10px; -webkit-appearance: none; -moz-appearance: none; appearance: none; border: 1px solid #999; background: #eee; background: url(arrow01.png) right 50% no-repeat, -webkit-linear-gradient(top, #fff 0%,#efebe1 100%); background: url(arrow01.png) right 50% no-repeat, linear-gradient(to bottom, #fff 0%,#efebe1 100%); background-size: 20px, 100%; } |
backgroundでは先に記述のあるものほど全面のレイヤーになります。
また、グラデーションは「画像」として扱われるため、グラデーションよりも矢印画像を先に記述しておかないと、矢印画像が隠れてしまうので注意してください。
この例では、Retina対応のために2倍の解像度で作成した画像を使用していますので、background-sizeで背景画像のサイズを調整しています。
もうひとつの方法
上の例では右端に矢印画像があるので問題ありませんが、例えば幅が成り行きのセレクトボックスに対し右端から20pxの位置に矢印画像を配置するようなデザインだった場合は、もう少し工夫が必要になります。
英語のソースになりますが、こちらで紹介されている方法を参考にさせていただきました。
HTML
label要素でselectを入れ子にしてください。
少し強引ですが、このlabel要素の「:after」疑似要素を使うことで矢印画像を固定位置に配置します。後から思ったのですが、labelを使わずにselect:afterでもいいような気がします。
<追記>select:afterは使えませんでした。
1 2 3 4 5 6 7 8 9 10 11 12 |
<div class="select-box02"> <label> <select> <option value="">セレクトボックス02</option> <option value="">選択肢01</option> <option value="">選択肢02</option> <option value="">選択肢03</option> <option value="">選択肢04</option> <option value="">選択肢05</option> </select> </label> </div> |
CSS
selectのスタイルはほとんどそのままです。
先の例との違いは、「position: relative;」が追加されたこと、矢印画像の指定がなくなったことだけです。
1 2 3 4 5 6 7 8 9 10 11 12 |
.select-box02 select { position: relative; width: 100%; padding: 10px; -webkit-appearance: none; -moz-appearance: none; appearance: none; border: 1px solid #999; background: #eee; background: -webkit-linear-gradient(top, #fff 0%,#efebe1 100%); background: linear-gradient(to bottom, #fff 0%,#efebe1 100%); } |
labelのCSSです。
「:after」疑似要素に矢印画像を指定し、絶対配置でセレクトボックスの右端20pxの位置に配置します。
ただしそのまま置いてしまうと、矢印部分をクリック(タッチ)した際にselectにフォーカスするだけでメニューが開かないということになってしまいます。
そこで、「:after」疑似要素に「pointer-events: none;」としておくことで、マウスイベントのターゲットから除外し、下に存在するselectが反応するようにしておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
.select-box02 label { position: relative; } .select-box02 label:after { display: block; content: " "; position: absolute; top: 50%; right: 20px; width: 20px; height: 20px; margin-top: -8px; background: url(arrow02.png) 0 0 no-repeat; background-size: 20px; pointer-events: none; } |
IE対応
IEはCSSのappearanceが使えず、IE11でさえ下のキャプチャのようになってしまいうまくいきません。

ただし、IE10以降であれば、「-ms-expand」疑似要素を使えばselectの矢印ボタンを非表示にすることができます。
1 2 3 |
select::-ms-expand { display: none; } |
残念ながら、IE9以下ではこの方法ではselectの矢印ボタンが消せませんので、意図した見た目にすることは厳しいです。「-ms-expand」を指定していても、IE9では下のキャプチャのようになってしまいます。

また、IE10でも「pointer-events」に対応していないようですので、2つ目の方法だと矢印画像部分でクリックできないという不具合が残ってしまいます。
まとめ
このサンプルの動作検証は、Chrome40、Firefox36-35、Safari6、IE11-10、iOS8、Android 4.1 で行ないました。
IE9以下への対応については上の説明の通りですが、基本的に切り捨てる方向かなと思います。
そもそもJavaScriptを使えばよいのかもしれませんが、個人的には不必要にスクリプトに依存したくないなという思いもあります。