2019年6月1日にCSSNite主催のwebアクセシビリティの学校に参加してきました。
ここでは詳細は記載しませんが、マシンリーダブルなコードを書くことへの意識が高まる1日でした。

アンケートの質問欄にフォームのコーディングについて質問を書いたところ、フォローアップで質問にご回答頂きました。
(質問採用されるのなかなか嬉しいですよね)
そこでfiledsetlegendというタグを知ったので、その使い方と調べていく過程で疑問に思ったテーブルレイアウトへの組み込み方をまとめていきます。先にお伝えしておくと、tableタグでは使えませんでした。

質問と回答内容

【質問】
フォームで氏名を入力する場面で、「氏名:姓[  ]名[  ]」のような場合、labelは姓と名だけにつければいいでしょうか?

【ご回答】
「姓」と「名」をlabel要素でマークアップするのに加えて、全体をfieldset要素で囲んで、「氏名」をlegend要素でマークアップすることで、全体をグループ化できます。
参考:H71: fieldset 要素及び legend 要素を使用して、フォームコントロールのグループに関する説明を提供する|WCAG 2.0 達成方法集

filedset…そんなタグがあるのですね。恥ずかしながら知りませんでした。
もちろんlegendタグも知りませんでした。
そこで、頂いた参考の他にいくつか情報をあたり自分なりに使い方を整理してみようと思います。

fieldsetとlegendの使い方

HTMLクイックリファレンスのfieldsetの項目には下記の記載がありました。

fieldsetタグは、フォームの入力項目をグループ化する際に使用します。 fieldset~fieldsetの中に配置された inputselecttextarea等のフォーム部品がグループ化され、一般的なブラウザではボーダーで囲まれて表示されます。

フォーム部品のグループにキャプション(タイトルや説明)を付ける場合には、fieldset~fieldsetの中の 最初のlegendで指定します。

また、disabled属性・form属性・name属性についても記載がありました。
内容をまとめると、

  • fieldsetを使ってフォームの項目をグループ化
  • タイトルや説明をつけるのにlegendを使う
  • disabled属性でグループ単位で無効化できる
  • formタグの外に配置するときはform属性とformのidを合わせて紐付けられる
  • name属性はスクリプトからの操作用に使う

なお、disabled属性・form属性・name属性はhtml5になって追加されたらしいです。

「氏名:姓[  ]名[  ]」をfieldsetを使ってコーディング

fieldsetの使い方がわかったところで、「氏名:姓[  ]名[  ]」という入力フォームを実際にコーディングしてみました。

form内にfieldsetを設置したパターン

See the Pen fieldset inside of form by Yuki Tomioka (@yuki-tomioka) on CodePen.

labelinputの紐付けはネストせずにfor属性とidを使ってもいいですね。

formの外にfieldsetを設置したパターン

See the Pen fieldset outside of form by Yuki Tomioka (@yuki-tomioka) on CodePen.

fieldsetはtableやdlの中で使えるのか

fieldsetの使い方はわかったのですが、ここでふとした疑問が浮かびました。
フォームのコーディングをするときtabledlタグを使うことが多いのですが、この場合fieldsetはどこに入れればいいだろうかという疑問です。

例えば下記のようなフォームがあったとします。

See the Pen form e.g. by Yuki Tomioka (@yuki-tomioka) on CodePen.

legendth内で氏名を囲えばよさそうですが、fieldsetはどこに入れればいいのでしょうか。
グループ化するという意味合いからtrの中か外の気もしますが、入れ子のルールとして違うタグは入れられないはずです。

考えてもわからなかったので、実際にコードを書いてツールで検証を行いました。検証にはNu Html Checkerを使いました。

試してみたコードその1

fieldsettrを囲ったパターン

<form>
  <table>
    <fieldset>
      <tr>
        <th>
          <legend>氏名</legend>
        </th>
        <td>
          <label for="family-name">姓</label>
          <input type="text" id="family-name">
          <label for="last-name">名</label>
          <input type="text" id="last-name">
        </td>
      </tr>
    </fieldset>
  </table>
</form>

検証結果

Nu Html Checkerでの検証結果

はい。予想通りがっつりエラーでした。

試してみたコードその2

fieldsettrの中に入れたパターン

<form>
  <table>
    <tr>
      <fieldset>
        <th>
          <legend>氏名</legend>
        </th>
        <td>
          <label for="family-name">姓</label>
          <input type="text" id="family-name">
          <label for="last-name">名</label>
          <input type="text" id="last-name">
        </td>
      </fieldset>
    </tr>
  </table>
</form>

検証結果

Nu Html Checkerでの検証結果

はい。こちらもエラーでした。

fieldsetをtableの中で使えるのか?の結論

結論は使えません

tableタグを使ってフォームを作る場合、構造上入れる場所がないのでtableの中でfieldsetを使うことができません。また、dlも直下に入れられるのはdtddのみなので同じようにfieldsetを使うことはできません。

fieldsetを使ってテーブルレイアウトのフォームを作る

テーブルレイアウトのフォームを作るときはどうすればいいのか、色々と検索していると次の記事に出会いました。

CSSが効かない!?fieldset要素でも簡単にテーブルレイアウトを実現できるdisplay: contents;

入力フォームでは、1つのキャプションとフォームコントロールのグループを横並びに配置するために、度々table要素が使われているように感じます。レイアウトを目的としてtable要素を利用すると、アクセシビリティ周りで発生するいくつかの問題を解決していかないといけません。

(上記記事本文より)

そうそうまさにこれです。
詳細はリンク先の記事を参照頂ければと思いますが、概要としては下記の通りです。

  • tableは使わずにCSSでテーブルレイアウトを作成する
  • fieldsetにはdisplay:tableが効かない
  • fieldsetdisplay:contentsを当ててdisplay上の関係性から切り離す
  • 他の要素にdisplay:tabletable-rowtable-cellを当ててテーブルレイアウトを実現する

実際のコードでみた方がわかりやすいかもしれません。

NGパターン

See the Pen 【NG】fieldset use in talbe layout by Yuki Tomioka (@yuki-tomioka) on CodePen.

OKパターン

See the Pen fieldset use in talbe layout by Yuki Tomioka (@yuki-tomioka) on CodePen.

display:contentsプロパティ自体の解説や他の使いどころはColissさんの[CSS]「display: contents;」がすごい便利!ラッパーを使った実装が大きく変わるこれからのテクニックがわかりやすかったです。

display:contentsの罠

やっと回答に辿りついたと思ったのですが、こんな記述が

ただ、display: contents;には注意点があります。サポートしているブラウザがまだ十分とは言えないというのもそうなのですが、本来この値はセマンティクスに影響を及ぼさないとされているところ、実はdisplay: contents;な要素がまるでdisplay: none;のようにアクセシビリティツリーから無視されてしまうというバグがモダンブラウザで確認されているのです。

そこで、Can I useで調べてみました。

Can I useで各ブラウザのdisplay:contents対応状況を調べた結果

IE、Edgeでは使えず、他のブラウザでも一部にバグがあるようです(2019年6月24日時点)。

WAI-ARIAのrole=”group”を使う

社内ツールなど使用するブラウザを限定することが可能な状況であればfiedlsetdisplay:contentsの組み合わせで対応できますが、一般向けのwebサイトなど多くの場合はIEやEdgeにも対応する必要があると思います。
その点を考えるとfieldsetの代わりにWAI=ARIAのrole=”group”を使ってdiv role="group"とし関連付けをするのが多くのケースで使えるコーディングとなりそうです。

まとめ

  • fieldsetを使うことでフォームのパーツをグループ化できマシンリーダブル性があげられる
  • legendを合わせて使うことで何のグループなのかを説明できる
  • fieldsetを使ってテーブルレイアウトを作るときはtableは使えず、display:contentsを使う
  • 多くのブラウザに対応するにはWAI=ARIAのrole="group"を使う

WAI-ARIAを使ってコーディングをしていない場合は、導入のための学習コストや社内理解などが必要になるというコーディングとは別の課題が出てきそうですね。

WAI-ARIAの基本として必要な時だけ使うとある通り、HTMLとCSSのみで実装できるよう各種ブラウザでfiledsetの扱いやdisplay:contentsの実装やバグフィックスが進むといいですね。

この記事を書いた人

Yuki Tomioka

元焼肉店店長からゼロシード株式会社の1人目のwebエンジニアとなる。テクニカルディレクターとして勤務し、WordPressのカスタマイズやアクセス解析や広告運用などに従事。現在は事業会社のフロントエンドエンジニアとして勤務。
タイムチケットで相談も受け付けてます。