フォームのマークアップについて考えてみる

ウノウラボで書いたエントリが被ブクマ400を超える未体験ゾーンに突入。デザインやUI系のネタが受けるのは分かっていたので、狙ってみた部分も正直あるけど、それにしても予想以上の反響です。

そこで書いた「チェックボックスラジオボタンはfieldset,label要素でくくる」という項目でいろんなご指摘を頂きました。エントリ自体はマークアップよりも、「フォームを使う人にとっての利便性をどう考えるか」が本旨なので、そこばかり注目されるのも本意ではなかったのですが、それだけ気になる部分なのだろうということで、場を改めて検証してみます。DTDはXHTML1.0 Strictを前提に。

■label要素のマークアップ

label要素を使用することで、ラベル部分をクリックすることで関連付けられたフォームコントロールにアクセス出来る、というのが基本的な挙動です。一般に、ラジオボタンチェックボックスを選択しやすくする目的で使われることが多いです。

ここをクリックしても無駄

このlabel要素のマークアップには、2通りのアプローチがあります。

明示的なラベル付け
<input type="radio" id="fav1" name="favorite" value="1" />
<label for="fav1">犬好き</label>

フォームコントロールにidを付け、そのidを持つ要素に対してラベルを付けるというアプローチです。

暗黙的なラベル付け
<label><input type="radio" name="favorite" value="1" />犬好き</label>

こちらはフォームコントロールをlabelに内包することで、関連付けを暗黙的に示すアプローチです。label要素はfor属性の指定が無い場合、自身の内包するフォームコントロールに対して関連付けられた物とみなします。label要素には他のlabel要素を含めることは認められません(参考:要素の禁止事項−XHTML1.0仕様邦訳)。
また、XHTML1.0のDTDには、

<!--
  Each label must not contain more than ONE field
  Label elements shouldn't be nested.
-->

という記述があります。

  • labelの中には2つ以上のフィールドを含めてはならない
  • label要素はネストしていならない

ということですかね。後者は前述の内容と同じですね。前者はlabelの中に複数のフォームコントロールを含めると、どの要素に対するラベルなのか分からないので禁止なのでしょう。
この場合、ラベリングの対象となる要素にidを設定する必要がないため、よりシンプルなマークアップが可能です。

IEの挙動

Win IE5/6では暗黙的なラベル付けをした場合にラベル部分がクリックできません。なので、実際のところはlabel要素のマークアップはidを指定した明示的なラベル付けが必須となります。IE7では暗黙的なラベル付けをした場合も、ラベル部分をクリックすることが可能です。
ちなみに、Safari2ではどちらで書いた場合もラベル部分をクリックすることは出来ません(Safari3では大丈夫らしいです)。

問題のマークアップ

当初自分がサンプルとして挙げていたコードでは、以下のように書いていました。

<label for="fav1"><input type="radio" id="fav1" name="favorite" value="1" />犬好き</label>

要素のツリー構造は「暗黙的なラベル付け」と同様ですが、IEでの挙動を補うためにidを指定して「明示的なラベル付け」として動作させています。これについて、「label内に、そのlabelの参照先であるinputが含まれるのはおかしいのではないか?」という指摘を頂きました。
自分としては、暗黙的なラベル付けをしたらIEがダメだったのでidを補った、ぐらいにしか考えていなかったのですが、考えてみればごもっとも。
このあたりの解釈に関する細かい資料を見たことがないのですが、「label要素にfor属性の指定が無い場合」に暗黙的なラベル付けが行われると考えるのが妥当でしょう。この場合は、labelに含まれるフォームコントロールがその対象であることが規定されているので、コントロールを内包していても問題ないはずです。パーサの挙動としては、labelの内容を解析して、その中にあったフォームコントロールに対して、それ以外の部分をラベルとみなすというアルゴリズムになるはずです。
しかし、idを指定した場合は単にlabelの内容が対象コントロールのラベルとなるだけのはずです。そのため、上記のコードでは、fav1の説明にfav1自身が含まれるという形になります。
今まで気にしていなかったのですが、確かにこの記述は(実害があるかは別として)不適切であるように思われます。

目に見える挙動の違い

マークアップの妥当性はさておき、実際のブラウザの挙動を見てみましょう。IE6では明示的・暗黙的なラベル付けでブラウザの挙動が変わります。

左がラジオボタンをlabelの外に置いた場合、右がlabelの中に置いた場合です。それぞれのラジオボタンを選択した時にIE6ではこのようにlabel要素の周りに点線が表示されます(他のブラウザでは何も出ません)。また、この表示を変更してみようとCSSでoutlineの指定をしてみましたが、どうやら効かないようでした(あまりしっかり検証していませんが)。
どちらがいいかは趣味の問題もあるでしょうが、右の方だと点線の上部が揃っていないので不格好な印象です。左の方が締まって見えますね。

ここまでのまとめ

idを指定しない暗黙的なラベル付けは、現行で圧倒的なシェアを誇るIE6でラベルがクリック出来ないので却下。idを付けて明示的にラベル付けをした場合、inputを中に含むことはマークアップの意味合いとしてもよろしくない上に、IE6のクリック時のアウトラインが美しくない。逆にメリットは何もないので、labelの中にはinputを含めるべきではない。ということですね。

■fieldset要素とlegend要素

もう一つ、元エントリでは「fieldsetでラジオボタンとかをグループ化しておくと、CSSで全体に背景色とか付けられて便利だよ」と紹介したところ、「fieldsetを使うならlegendも一緒に使うべき」という指摘がありました。来るかなぁという気はしながらも、まぁそこまで厳密にしなくてもいいかと思ったらやっぱり突っ込まれた。

このlegend要素というのは、fieldsetで囲ったフォームコントロールのグループに対するラベル指定を表す物です。DTDでは以下のようにコメントされています。

<!--
  The fieldset element is used to group form fields.
  Only one legend element should occur in the content
  and if present should only be preceded by whitespace.
-->

「fieldsetでグループ化したら、そこにlegend要素を1つ含むべき」ということですね。このlegend要素については、The Web KANZAKIさんに詳細な解説があるので、そちらを参照してください(参照:コントロールをグループ化する|フォームとアクセシビリティ)。
こちらによると、HTML4.01ではDTD上でfieldsetに対するlegend要素が必須の物として規定されているそうです。が、XHTML1.0ではコメントによる記述にとどまっています。これがDTDのフォーマット的な理由からなのか、規定が弱まったからなのかはよく分かりません。

ただ、このlegend要素を使うと、そこに設定したラベルも表示されちゃうんですよね。当然ですけど。で、実際にはこれを表示したくない場合というのも多々ある、というかむしろその方が多いように思います。この時にどうするかと言うと、「XHTMLにはlegendを記述して、CSSでdisplay:noneとかやって非表示にする」というアプローチに恐らくなります。まぁでも、それって面倒だよね、というかぶっちゃけ意味ないんじゃね? と思っちゃう訳ですよ。音声ブラウザとか、非視覚系UIに向けてとかいう話自体は分からなくもないけど、じゃあ実際にここでlegendを書くことがどれだけの効果があるかよく分からない。自分のリソースの中で出来ることというのは限られてる訳で、だったらそこのマークアップに手をかけるよりももっと別のことにリソースを注ぎ込みたいと思ってしまいます。

アクセシビリティという概念やその取り組み自体はいいことだと思うけど、そもそもそれってマークアップに少し手を入れた程度でどうにかなる物なのかという疑問もあります。本当にそういう取り組みをするなら音声ブラウザでの読み上げチェックは当然必要だろうし、コンテンツの企画やライティングも含めてやらないとあまり意味はないような気がします。

公共性の高いところ(役所系とか)はそういうところもしっかり対応して欲しいと思いますけどね。結局はそのサービスを使うのは誰なのか、あるいは誰に使って欲しいのかということを踏まえて、そこに対してリソースを割いていくということに尽きるのでは無いかと思います。