TT Lab
はじめる
学ぶ 学習パス コース

HTML — タグ一つが機能を肩代わりする

名前のない入力欄は存在しない入力欄だ

TT Labで続きを見る

一言でいうと

フォームコントロールのアクセシブルネーム(accessible name)は、マークアップにlabelという文字があるかどうかではなく、決められた順序に従って計算された結果です。その計算を知らないと、labelをすべて書いたのに名前のない入力欄を作ってしまいます。

なぜ必要なのか

サインアップフォームで人がつまずく場所は、いつも同じです。送信を押したのに、何も起きません。画面のどこかが赤くなったのでしょうが、スクリーンリーダーのユーザーには何の音も出ず、キーボードのユーザーにはフォーカスがそのままボタンに残っています。

このとき、マークアップを開いてみると、labelもあり、requiredもあります。ところがfor="mail"なのに、入力欄はid="email"です。目では並んでくっついているように見えるため、誰も気づきません。機械にとって、その2つは赤の他人で、その入力欄の名前はありません。

名前のない入力欄を、スクリーンリーダーは「編集」とだけ読み上げます。何を入れる欄なのかを知る方法がありません。そして、この欠陥は、自動検査ツールが「label要素がある」として通過させてしまうことが多いため、長く生き残ります。

どう動くのか

HTML-AAMは、コントロールの種類ごとに、名前を求める順序を決めています。文字を入力する入力欄とtextareaは、こうです。

1. aria-labelledby  — 가리킨 요소들의 글자를 이어 붙인다
2. aria-label       — 속성값 그대로
3. 연결된 label      — for/id 또는 감싼 label 의 글자
4. title            — 마우스를 올려야 보이는 그것
5. placeholder      — 글자를 치면 사라지는 그것

このコードブロックの韓国語コメントは、順に、参照した要素の文字をつなげる、属性値をそのまま使う、for/idで関連付けられたlabelまたは囲んでいるlabelの文字を使う、マウスを重ねないと見えないもの、文字を入力すると消えるもの、という意味です。

HTML Accessibility API Mappings 4.1節とAccessible Name and Description Computationが原典です。

ここで重要なことが2つあります。

1つ目は、前の段階が1つでも値を出せば、後ろは見ないことです。そのため、aria-label="이메일"(韓国語で「メール」を意味する語です)を付けておくと、目に見えるlabelの文字が何であっても、スクリーンリーダーはaria-labelだけを読み上げます。画面には「会社メール」と書かれているのに、音声は「メール」と言う画面は、こうして作られます。音声で操作するユーザーは、見えている文字を呼ぶため、このずれは、その人にとっては操作そのものができない問題になります。

2つ目は、placeholderも名前にはなります。そのため、検査ツールが「名前なし」として検出してくれません。しかし、文字を入力した瞬間に消える名前なので、長いフォームで戻ってきたときに、何を書く欄だったのかを確認する方法がありません。弱視のユーザーにとっては、コントラストも不足しています。

グループにはグループの名前が必要です

ラジオボタンは、1つ1つが答えなのではなく、複数が集まって1つの質問を成します。各選択肢にlabelを付けても、「メール、ラジオボタン、選択済み」までしか読み上げられません。何を選んでいる最中なのかは、どこにも示されません。

fieldsetでグループ化してlegendを与えると、そのグループに名前が付きます。すると、「通知を受け取る方法、メール、ラジオボタン」のように、質問と答えが一緒に読み上げられます。

エラーは色ではありません

赤い枠線は、色を区別できない人にとっては何でもなく、画面を見ない人にとっては存在すらしません。プログラムが読み取れる信号が別に必要です。

aria-describedbyは、複数のidをスペースで並べて指定できます。そのため、ヘルプとエラーメッセージを一緒に指すようにしておけば、エラーが表示されても、「12文字以上」のようなルールの案内が消えません。エラーが出たときにルールを消してしまう実装が、意外とよくあります。

現場での姿

WCAGのLabels or Instructionsは、「入力が必要なときは、ラベルまたは説明を提供する」とだけ述べています。実務でこの1行が破られる形は、たいてい3つです。

  1. デザインの見栄えのために、labelを消してplaceholderだけを残します
  2. コンポーネントを再利用する際にidを固定値にしてしまい、1つの画面で2回使うとidが重複します。重複した瞬間、後ろのlabelは前の入力欄を指します
  3. エラーメッセージをaria-describedbyに差し替えてしまい、ルールの案内が消えます

3つとも、マウスで確認すれば問題なく見えます。そのため、このコースは、検査ツールを実行して、名前がどこから来たのかを目で確認するところから始めます。出どころがlabelなら安全で、placeholderやtitleなら消える名前であり、空なら、その入力欄は存在しないも同然の欄です。

また、autocompleteを正しく指定することもアクセシビリティです。手を使うのが難しい人にとって、タイプの回数はそのままコストであり、HTML標準のautofillのフィールド名にない値は、ブラウザーが単に無視します。autocomplete="e-mail"は何も行いません。

次のラボですること

サインアップフォームを1つ書き、入力欄ごとに名前がどこから来たのかを計算ツールで確認します。placeholderから来ている名前をlabelに移し、ラジオをfieldsetでグループ化し、エラーをプログラムが読み取れるようにします。最後に、計算ツールの結果をファイルに残します。