HTMLフォームのプルダウンにselected属性を付けるべき理由

HTMLでフォームを作った際、プルダウンやリストボックスにdisabled属性を設定したときの挙動がブラウザによって異なるのが興味深かったのでまとめてみます。

  1. option要素、optgroup要素のdisabled属性
  2. option要素のselected属性

option要素、optgroup要素のdisabled属性

input要素やtextarea要素などのフォームコントロールには、それを無効にするdisabled属性(www.w3.org)があります。

変更を不可にするreadonly属性と異なり、入力・選択ができなくなるだけでなく、フォーカスが合うことはなく、値の送信も行われません。たとえば次のフォームを送信した場合、 form.php には foo=hoge&baz=fuga しか送られません。

<form action="form.php">
  <p><input name="foo" value="hoge" /></p>
  <p><input name="bar" value="piyo" disabled="disabled" /></p>
  <p><input name="baz" value="fuga" readonly="readonly" /></p>
  <p><button type="submit">送信</button></p>
</form>

ところが、プルダウンやリストボックスの場合はdisabled属性に対応していなかったり、挙動のおかしなブラウザが存在します。

option要素に設定した場合、optgroup要素に設定した場合など4パターンにてテストしてみます。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>プルダウンやリストボックスにdisabled属性を設定してみる</title>
</head>
<body>
<form action="">
  <p>
    <select name="s1" id="s1">
      <option value="0" disabled="disabled">選択不能</option>
      <option value="1">選択可</option>
    </select>
    <label for="s1">option要素にdisabled属性を設定</label>
  </p>
  <p>
    <select name="s2" id="s2" multiple="multiple">
      <option value="0" disabled="disabled">選択不能</option>
      <option value="1">選択可</option>
    </select>
    <label for="s2">option要素にdisabled属性を設定(multiple)</label>
  </p>
  <p>
    <select name="s3" id="s3">
      <optgroup label="グループ1" disabled="disabled">
      <option value="0">選択不能</option>
      </optgroup>
      <optgroup label="グループ2">
      <option value="1">選択可</option>
      </optgroup>
    </select>
    <label for="s3">optgroup要素にdisabled属性を設定</label>
  </p>
  <p>
    <select name="s4" id="s4" disabled="disabled">
      <option value="0">選択不能</option>
    </select>
    <label for="s4">select要素にdisabled属性を設定</label>
  </p>
  <p><button type="submit">送信</button></p>
</form>
</body>
</html>
画像1Firefox13 の表示
画像2iPhone4(Safari) の表示

このHTMLを、PCとスマートフォンの代表的なブラウザで表示させた場合の違いを表にしました。ただし、4つ目の「select要素にdisabled属性を設定」したものは、いずれのブラウザもコントロールごと無効になったので省略します。

Firefox13, IE8以降 Chrome19 Safari5.1 Opera12 iPhone, iPad Android
option要素にdisabled属性 disabledな選択肢は無効となり、有効なうち最初のものが初期選択 Fx, IEと同じ 最初の選択肢がdisabledでも初期選択されるが、そのまま送信しても値は送られない Fx, IEと同じ disabledな選択肢も選択可能だが、その場合は値は送られない 最初の選択肢がdisabledでも初期選択され、そのまま送信すると値が送られる (いちど選択を外すと二度と選択できない)
multipleなoption要素にdisabled属性 disabledな選択肢は無効となる Fx, IEと同じ Fx, IEと同じ Fx, IEと同じ option要素に設定した場合と同じ Fx, IEと同じ
optgroup要素にdisabled属性 option要素に設定した場合と同じ disabledな選択肢は無効とならず、値も送られる option要素に設定した場合と同じ 最初の選択肢がdisabledでも初期選択され、そのまま送信すると値が送られる (いちど選択を外すと二度と選択できない) option要素に設定した場合と同じ option要素に設定した場合と同じ (Operaと同じ)
上記HTMLで何も変更せずボタンを押した時の送信データ s1=1&s3=1 s1=1&s3=0 (なし) s1=1&s3=0 (なし) s1=0&s3=0

主な注目点をまとめてみます。

  • FirefoxとIEの動作には、不自然な点は見当たらない
  • Google Chromeは、optgroup要素に対するdisabled属性に対応していない
  • iPhoneやiPadのSafariは、disabledな選択肢も選択できるが、その場合は値は送信されない
  • (表には含めていないが)IE7以前は、option要素とoptgroup要素に対するdisabled属性に対応していない。select要素に設定した場合を除き、未設定時と同じ状態になる。

と、このようにブラウザによって表示や挙動がまちまちです。しかしながら、そもそも一部要素に対するdisabled属性の指定が無視されるGoogle ChromeやIE7以前は別として、これらはブラウザの実装が貧弱なわけではなく、先に挙げたHTMLにも問題があります[1]

option要素のselected属性

option要素にselected属性を設定すると、初期状態で選択済み状態になりますが、HTML4.01では次のような記述があります。

If no OPTION element has the selected attribute set, user agent behavior for choosing which option is initially selected is undefined.

(中略)

authors should ensure that each menu includes a default pre-selected OPTION.

17.6.1 Pre-selected options(www.w3.org)

すなわち、select要素には必ず1つはselected属性の付いたoption要素がないといけないのです。なお、ラジオボタンも同じような規定(www.w3.org)があり、1つchecked属性を設定しなければなりません。

実際のブラウザの動作を見ると、checked属性のないラジオボタンはいずれも選択されない状態となる一方、selected属性のないプルダウンは一番目の選択肢が選択されるケースが多いので、たまたま一番目がデフォルト値な場合はselected属性が書かれないケースが多い気がします。いずれにしても、プルダウンのoption要素には必ずひとつselected属性を付けるようにしましょう。SafariやOpera、Android標準ブラウザでは先に挙げたような問題がなくなります。

ただし、Google Chromeがoptgroup要素のdisabled属性に対応していなかったり、iPhoneやiPadのSafariでdisabledな選択肢も選択できてしまう問題は解決しません。可能であればJavaScriptでDOMから除去してしまうのが良いと思います。

  • [1]とはいえiPhone, iPadの挙動はどう考えてもおかしいと思います。