フォームの構築方法

基本から外れて、ここでは色々なフォームのパーツを構造化し、意味をつけるのに使われる要素を詳しく見ていきます。

前提条件: 基本的なコンピューターリテラシーと、HTML の基本的な理解
目的: HTML フォームを構造化して意味を与えて使いやすくアクセシブルにする方法を理解すること。

フォームは柔軟性があるため、HTML で最も複雑な構造の 1 つとなっています。専用のフォーム要素と属性を使用して、あらゆる種類の基本フォームを作成できます。HTML フォームを構築するときに正しい構造を使用すると、フォームが使用可能でアクセスしやすいことを確実にするのに役立ちます。

<form> 要素

<form> 要素はフォームを正式に定義するとともに、自身の属性でフォームの動作を定義します。HTML フォームを作成しようとするたびに、この要素から始めて、すべてのコンテンツをその中に入れなければなりません。多くの支援技術やブラウザープラグインは <form> 要素を検出でき、またフォームを使いやすくするための特別なフックを実装できます。

前の記事ですでにこれを見ています。

警告: フォームの中にフォームを入れ子にすることは厳格に禁じられています。これは予期せぬ動作を発生するおそれがあるので、悪い方針です。

<form> 要素の外部でもフォームウィジェットを使用できますが、そのフォームウィジェットは form 属性を用いて関連付けなければ、どのフォームに対しても何も行わないことに注意してください。これは、実際には <form> に包含されていない要素であっても明示的にフォームへ紐付けることを可能にします。

  次に、フォームに含まれる構造的な要素を見ていきましょう。

<fieldset> および <legend> 要素

<fieldset> 要素は、スタイルや意味付けのために、同じ目的を持つウィジェットのグループの作成に便利です。<fieldset> 要素は、<fieldset> タグのすぐ下に <legend> 要素を入れてラベルを付与できます。<legend> 要素は、<fieldset> 要素の目的を正式に説明します。

多くの支援技術は <legend> 要素を、対応する <fieldset> 要素内にある各ウィジェットのラベルの一部であるかのように扱うでしょう。例えば JawsNVDA といったスクリーンリーダーは、各ウィジェットのラベルを読み上げる前に legend の内容を読み上げます。

以下に小さなサンプルを挙げます:

<form>
  <fieldset>
    <legend>Fruit juice size</legend>
    <p>
      <input type="radio" name="size" id="size_1" value="small">
      <label for="size_1">Small</label>
    </p>
    <p>
      <input type="radio" name="size" id="size_2" value="medium">
      <label for="size_2">Medium</label>
    </p>
    <p>
      <input type="radio" name="size" id="size_3" value="large">
      <label for="size_3">Large</label>
    </p>
  </fieldset>
</form>

: この例は fieldset-legend.html で見ることができます(ライブ版も見てください)。

この例では、スクリーンリーダーは最初のウィジェットを "Fruit juice size small"、2 番目を "Fruit juice size medium"、3 番目を "Fruit juice size large" と読み上げるでしょう。

このサンプルでのユースケースは、もっとも重要なことのひとつです。ラジオボタンのセットを置くたびに、それらを <fieldset> 要素内へ入れ子にするようにしましょう。ユースケースは他にもあり、通常は <fieldset> 要素でフォームを明確に区分するために使用できます。理想的には長いフォームは複数ページに分けるべきですが、フォームが長くなっても1つのページに収めないといけない場合、別々の関連セクションを別々の fieldset に入れることは使いやすさを改善します。

支援技術への影響力により、<fieldset> 要素はアクセシブルなフォームを作成するために重要な要素のひとつです。しかし、それを誤用しないようにするのはあなたの責務です。できれば、フォームを作成するたびにスクリーンリーダーがどのように解釈するか聞いてみましょう。変に聞こえるのであれば、フォームの構造を改善するためのよいヒントになります。

<label> 要素

これまでの記事で見てきたように、<label> 要素は、HTML フォームウィジェットのラベルを定義する正式な方法です。これは、アクセシブルなフォームを作成したい場合にもっとも重要な要素です — 適切に実装された時は、スクリーンリーダーはフォーム要素のラベルと関連する指示を一緒に読み上げます。前の記事で見てきたこの例を見てみます:

<label for="name">Name:</label> <input type="text" id="name" name="user_name">

<label><input> とがそれぞれ forid 属性により正し関連付けられると (label の for 属性は対応するウィジェットの id 属性を参照します)、スクリーンリーダーは "Name, edit text"のように読み上げます。

フォームコントロールとラベルを関連付けるもう 1 つの方法は、フォームコントロールを <label> の中でネストすることで、暗黙的に関連付けることです。

<label for="name">
  Name: <input type="text" id="name" name="user_name">
</label>

この場合でも for 属性を設定することがベストプラクティスと考えられています。これは、ラベルとウィジェットの暗黙的な関係を理解できない支援技術があるためです。

ラベルがなかったり、フォームコントロールが明示的/暗黙にラベルに関連付けられていない場合、スクリーンリーダーは全く役立たない "Edit text blank" のような読み上げを行います。

ラベルもクリック可能です!

ラベルをセットアップするもう 1 つの利点は、ユーザーがラベルをクリックするとウィジェットをアクティブにすることが、あらゆるブラウザーで可能になります。これは例えば、テキスト入力で、入力と同様にラベルをクリックしてフォーカスさせることができますし、ラジオボタンやチェックボックスで特に有用です — このコントロールのヒットエリアはとても小さく、できるだけ大きくしておくのは便利です。

例えば、次の例で "I like cherry" の テキストをクリックすると選択された taste_cherry チェックボックスの状態が切り替わります:

<form>
  <p>
    <input type="checkbox" id="taste_1" name="taste_cherry" value="cherry">
    <label for="taste_1">I like cherry</label>
  </p>
  <p>
    <input type="checkbox" id="taste_2" name="taste_banana" value="banana">
    <label for="taste_2">I like banana</label>
  </p>
</form>

: この例は checkbox-label.html で見ることができます(ライブ版も見てください)。

複数のラベル

厳密に言うと、1 つのウィジェット内に複数のラベルを入れることができますが、複数のラベルを持つウィジェットの扱いに問題がある支援技術があるかもしれません。複数のラベルがある場合、アクセシブルなフォームを作成するには1つの <label> 要素内にウィジェットを入れ子にするとよいでしょう。

以下のサンプルについて考えてみましょう:

<p>Required fields are followed by <abbr title="required">*</abbr>.</p>

<!-- 2 つの例をご覧ください: -->
<div>
  <label for="username">Name:</label>
  <input id="username" type="text" name="username">
  <label for="username"><abbr title="required" aria-label="required">*</abbr></label>
</div>

<!-- 前出の例よりは良いです: -->  
<div>
  <label for="username">
    <span>Name: </span>
    <input id="username" type="text" name="username">
    <abbr title="required" aria-label="required">*</abbr>
  </label>
</div>

<!-- これが最も良いでしょう: -->
<div>
  <label for="username">Name: <abbr title="required" aria-label="required">*</abbr></label>
  <input id="username" type="text" name="username">
</div>

このサンプルでは、最初の段落で入力必須の要素の規則を定義しています。ユーザーが入力必須の要素を見つける前にスクリーンリーダーのような支援技術が注意事項を表示したり読み上げたりするためには、規則をはじめに置かなければなりません。これがユーザーにアスタリスクの意味を知らせても、それに依存することはできません。スクリーンリーダーはアスタリスクが出てくると "スター" と読み上げます。視力のあるユーザーがマウスを持ってくると、title 属性によって"必須"と表示されます。タイトルはスクリーンリーダーの設定により読み上げられるので、常にスクリーンリーダーに読み上げられる aria-label 属性を入れておくのがより信頼性が高いでしょう。

上記の違いをふまえると、以降を効率よく見ていけるでしょう:

  • 最初の例では、label 要素すべての入力が読み上げられません  — "edit text blank" だけです。その上に実際のラベルは別々に読まれます。複数の <label> 要素はスクリーンリーダーを混乱させます。
  • 2 つ目の例では、少し明確になります "name star name edit text required" というようにラベルが入力と一緒に読み上げられます。しかしラベルはまだ別々に読み上げられます。少し混乱しやすいですが、これは <input> と関連したラベルがあるためまだ良いでしょう。
  • 3 つ目の例が最も良いです — 実際のラベルがすべて一緒に読み上げられ、"name required edit text" のようにラベルと入力が一緒に読み上げられます。

: スクリーンリーダーによっては、少し異なる結果になる場合もあります。これは VoiceOver (と同様に動作する NVDA)でテストしています。あなたの体験を聞きたいです。

: この例は GitHub の required-labels.html で見ることができます(ライブ版も見てください)。2 や 3 のコメントを外したバージョンの例を実行しないでください — 複数の label と複数の同じ input ID があると、スクリーンリーダーは確実に混乱します!

フォームで使用される一般的な HTML 構造

ウェブフォーム特有の構造の前提として、フォームは単に HTML であると覚えておくとよいでしょう。つまり、ウェブフォームを組み立てるために HTML のすべての力を利用できるのです。

サンプルでわかるように、ラベルとそのウィジェットを <ul><ol> リストの中の <li> 要素で包み込むのが一般的な慣習です。HTML リストにあるように、<p> 要素と <div> 要素も良く使われます。リストは複数のチェックボックスやラジオボタンを構造化するのに最もよく使われます。

<fieldset> 要素に加えて、複雑なフォームの構築に HTML の見出し (例<h1>, <h2>) やセクション (例 <section>) を使うことも一般的です。

とりわけ、コーディングスタイルがどうあるのが心地よく、どれがアクセシブルで使いやすいフォームとなるのかを見つけるのはあなた次第です。別の機能セクションは別の <section> 要素と、ラジオボタンを含む <fieldset> にそれぞれ分けておくべきです。

アクティブラーニング: フォーム構造を構築する

これらのアイデアを実践し、もう少し複雑なフォーム構造、つまり支払いフォームを作成しましょう。このフォームはあなたがまだ理解していないかもしれないウィジェットタイプをいくつも含みますが、今はそのことを心配しないでください。次の記事 (ネイティブフォームウィジェット) でそれらがどのように機能するのかがわかります。今のところ、以下の説明に沿って説明を注意深く読み、フォームを構成するためにどのラッパー要素を使用しているか、そしてその理由を理解することから始めてください。

  1. あらかじめ、空のテンプレートファイルお支払いフォームの CSS のローカルコピーをコンピューターの新しいディレクトリーに作成します。
  2. まず最初に、HTML <head> 内に次の行を追加して CSS を HTML に適用します。
    <link href="payment-form.css" rel="stylesheet">
  3. 次に、外側の <form> 要素を追加してフォームを作成します:
    <form>
    
    </form>
  4. <form> タグ内に、必須フィールドにマークを付ける方法をユーザーに通知するための見出しと段落を追加します:
    <h1>Payment form</h1>
    <p>Required fields are followed by <strong><abbr title="required">*</abbr></strong>.</p>
  5. 次に、前のエントリーの下に、より大きなコードセクションをフォームに追加します。ここでは、連絡先情報フィールドを個別の <section> 要素内にラップしていることがわかります。さらに、2 つのラジオボタンのセットがあり、それぞれ独自のリスト (<li>) 要素の中に入れています。最後に、2 つの標準テキスト <input> とそれに関連する <label> 要素があり、それぞれ <p> の内側に含まれていて、パスワードを入力するためのパスワード入力があります。フォームにこのコードを追加してください:
    <section>
        <h2>Contact information</h2>
        <fieldset>
          <legend>Title</legend>
          <ul>
              <li>
                <label for="title_1">
                  <input type="radio" id="title_1" name="title" value="K" >
                  King
                </label>
              </li>
              <li>
                <label for="title_2">
                  <input type="radio" id="title_2" name="title" value="Q">
                  Queen
                </label>
              </li>
              <li> 
                <label for="title_3"> 
                  <input type="radio" id="title_3" name="title" value="J">
                  Joker 
                </label> 
              </li>
          </ul>
        </fieldset>
        <p>
          <label for="name">
            <span>Name: </span>
            <strong><abbr title="required">*</abbr></strong>
          </label>
          <input type="text" id="name" name="username">
        </p>
        <p>
          <label for="mail">
            <span>E-mail: </span>
            <strong><abbr title="required">*</abbr></strong>
          </label>
          <input type="email" id="mail" name="usermail">
        </p>
        <p>
          <label for="pwd">
            <span>Password: </span>
            <strong><abbr title="required">*</abbr></strong>
          </label>
          <input type="password" id="pwd" name="password">
        </p>
    </section>
  6. それでは、フォームの 2 番目の <section> — 支払い情報に目を向けます。ここには 3 つの異なるウィジェットとそのラベルがあり、それぞれ <p> の中に含まれています。1 つ目は、クレジットカードの種類を選択するためのドロップダウンメニュー (<select>) です。2 番目は、クレジットカード番号を入力するための tel 型の <input> 要素です。number 型を使うこともできますが、そのスピナーUIは望ましくありません。最後のものは、カードの有効期限を入力するための date 型の <input> 要素です。これは、サポートしているブラウザーでは日付選択ウィジェットが表示され、サポートしていないブラウザーでは通常のテキスト入力に戻ります。新しい入力タイプは HTML5 入力タイプで再度紹介されます。
    もう一度、前のセクションの下に次のように入力します。
    Enter the following below the previous section:
    <section>
        <h2>Payment information</h2>
        <p>
          <label for="card">
            <span>Card type:</span>
          </label>
          <select id="card" name="usercard">
            <option value="visa">Visa</option>
            <option value="mc">Mastercard</option>
            <option value="amex">American Express</option>
          </select>
        </p>
        <p>
          <label for="number">
            <span>Card number:</span>
            <strong><abbr title="required">*</abbr></strong>
          </label>
          <input type="tel" id="number" name="cardnumber">
        </p>
        <p>
          <label for="date">
            <span>Expiration date:</span>
            <strong><abbr title="required">*</abbr></strong>
            <em>formatted as mm/dd/yyyy</em>
          </label>
          <input type="date" id="date" name="expiration">
        </p>
    </section>
  7. 最後に追加するセクションはもっと単純で、フォームデータを送信するための submit タイプの <button> のみを含みます。これをフォームの一番下に追加してください:
    <p> <button type="submit">Validate the payment</button> </p>

完成したフォームは以下のように動作しています (GitHub でも確認できます。payment-form.html ソースを参照してライブ実行してください)。

まとめ

ウェブフォームを適切に構築するためのあらゆる知識を得ることができました。これからここで出てきた機能を見ていき、次の記事では、ユーザーから情報を集めるのに使いたくなるすべての種類のフォームウィジェットの詳細な実装について詳しく見ていきます。

関連情報

このモジュール

上級トピック