横幅が自動調整されるHTMLドロップダウンリスト

会社の同僚にHTMLのドロップダウンリストでコントロールの横幅は固定でドロップダウンされるリストの横幅だけ中の項目のサイズに合わせて調整したいと言われたので(説明へたやなぁ)、jQueryでさくっと(実際にはさくっとはいかなかったけど)作ってみた。

jquery.dropdown.js

jQuery.fn.extend({
   dropdown: function(opt) {
       var defOpt = {
           buttonWidth: "22px",
           buttonHeight: "22px",
           dropdownSize: 5,
           dropdownWidth: ""   // AutoSize
       };
       var option = opt ? opt : {};
       // 値のチェック
       if(!option.buttonWidth) option.buttonWidth = defOpt.buttonWidth;
       if(!option.buttonHeight) option.buttonHeight = defOpt.buttonHeight;
       if(!option.dropdownSize) option.dropdownSize = defOpt.dropdownSize;
       if(!option.dropdownWidth) option.dropdownWidth = defOpt.dropdownWidth;

       var container = $("<div>")
           .css({
               "display": "block",
               // オリジナルからマージンを継承するいい方法が思いつかなかった
               "margin": [
                   this.css("margin-top"),
                   this.css("margin-right"),
                   this.css("margin-bottom"),
                   this.css("margin-left")
               ].join(" "),
               // 同様
               "padding": [
                   this.css("padding-top"),
                   this.css("padding-right"),
                   this.css("padding-bottom"),
                   this.css("padding-left")
               ].join(" ")
           });
        
       var frame = $("<div>")
           .width(this.width())
           .height(option.buttonHeight)
           .css("border", "solid 1px silver");

       var label = $("<div>")
           .text(this.val().toString())
           .width(this.width() - parseInt(option.buttonWidth) - 2)
           .css({
               "float": "left",
               "display": "inline",
               "overflow": "hidden",
               "padding-top": "3px",
               "padding-left": "2px",
               "font-size": this.css("font-size"),
               "font-family": this.css("font-family")
           });

       var values = this.clone()
           .width(option.dropdownWidth)
           .attr("size", option.dropdownSize)
           .css({
               "float": "left",
               "display": "none",
               "position": "absolute",
               "margin": "0px",    // オリジナルから受け継いだマージンは消去する
               "margin-top": "2px",
               "border": "solid 1px silver"
           })
           .change(function() {
               label.text(
                   $(this).hide().find(":selected").text()
               );
           });
        
       var button = $("<button>")
           .text("▼")
           .width(option.buttonWidth)
           .height(option.buttonHeight)
           .css({
               "float": "right",
               "font-size": "9px",
               "text-align": "center"
           })
           .click(function() {
               values.slideToggle("fast", function() { values.focus(); });
           });

       container.append(
           frame.append(label, button), values
       );
       this.after(container).remove();
        
       return this;
   }
});

やってることは元のドロップダウンリストを削除して、その代わりにdivとかbuttonを使ってドロップダウンリストっぽいものを作っているだけ。
元のドロップダウンリストのIDやら属性やらはそのまま引き継いでいるので、選択された値を取得する時なんかは元のIDを指定すればいい。

使い方

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
   <title>jQuery sample</title>
   <script type="text/javascript" src="jquery-1.2.3.pack.js"></script>
   <script type="text/javascript" src="jquery.dropdown.js"></script>
   <script type="text/javascript">
       $(document).ready(function() {
           $("#listbox1").dropdown();
            
           // 横幅指定
           $("#listbox2").dropdown({
               dropdownWidth: "200px"
           });
            
           // ドロップダウンリストの項目数
           $("#listbox3").dropdown({
               dropdownSize: 10
           });
       });
   </script>
</head>
<body>
   <div style="margin-left: 20px;">
       <select id="listbox1" style="width:100px;">
           <option>100000000000</option>
           <option>200000</option>
       </select>
        
       <select id="listbox2" style="width:150px; margin-top:5px">
           <option>100000000000</option>
           <option>200000</option>
           <option>300000</option>
       </select>
        
       <select id="listbox3" style="width:120px; margin-top:5px">
           <option>100000000000</option>
           <option>200000</option>
           <option>300000</option>
           <option>400000</option>
           <option>500000</option>
           <option>600000</option>
       </select>

       <input type="text" style="margin-top: 5px;" />
   </div>
</body>
</html>

スクリーンショット

jQuery拡張機能として作ってみたけど、結構いい感じ。
元のドロップダウンリストのスタイルをどれだけ引き継ぐか迷ったけどマージンとパディングだけにしておいた。他にもオプションで見た目のカスタマイズとかできるようにした方がいいんだろうけど、普通に使う分にはこれで十分だと思う。

一応IE6/7とFirefox2で動作確認済み。

ソース