トピックを検索
入力の途中で読まれてしまうか、まったく読まれないエラーメッセージ
メール欄のエラーをキーごとにアラートで送ると入力の途中で読まれてしまい、欄を離れたときに黙って出すと、まったく読まれない
email.addEventListener('input', check); 問題
スクリーンリーダーの利用者は、メールアドレスを入力している途中でエラーを聞かされるか、離れた欄に残ったエラーをまったく聞けない
紅茶の店のチェックアウトで、最初にメールアドレスを、その下に電話番号を尋ねています。アドレスはブラウザー側で確かめるため、誤りがあると、注文を送る前に欄の下へ「メールアドレスを「[email protected]」のような形式で入力してください」と表示されます。画面が見える人には、このメッセージが赤い文字で現れます。スクリーンリーダーの利用者に何が聞こえるかは、確認がいつ動くかによって変わります。この店のフォームは、よくある二通りの作り方の両方で作られています。
一つ目の作り方では、キーを押すたびに欄を確かめ、メッセージをアラートとして送ります。スクリーンリーダーの利用者が「s」と打つと、その文字に続けて、重なるように「メールアドレスを「[email protected]」のような形式で入力してください」と読まれます。まだ1文字しか打っていません。数文字先の「sam@s」はアドレスとして正しいためメッセージは消えますが、「sam@shop,」でまた誤りになり、そのあとに打つ文字に重なって、アラートがもう一度読まれます。今打っている途中のアドレスへのエラーなのか、打とうとしたアドレスへのエラーなのか、聞き分けられません。
二つ目の作り方では、欄を離れたときにだけ確かめ、メッセージを欄の下のただの段落に出します。同じ利用者がドットの代わりにカンマを打って「sam@shop,com」と入力し、Tabキーを押します。スクリーンリーダーは「電話番号(任意)、編集テキスト」と読むだけです。エラーは画面上に出ていますが、場所はもう離れた欄の下です。戻っても「メールアドレス、編集テキスト、必須、sam@shop,com」と読まれ、何かがおかしいことは伝わりません。注文が送れなくなって、初めて気づきます。
フォーカスを動かさずに現れるエラーは、ステータスメッセージです。達成基準4.1.3は、操作の結果や「エラーの存在」を伝える変化をステータスメッセージと定義し、フォーカスを受け取らずに役割やプロパティによって利用者へ伝えられることを求めています。Understandingのページは、それを「作業を不必要に妨げない形で」行うべきだとし、重要でも急ぎでもない内容への role="alert" や aria-live="assertive" を失敗例に挙げています。一つ目の作り方では、キーを押すたびに確認が動き、メッセージが変わるたびにアラートへ書き込まれます。入力途中のアドレスへのエラーは、重要でも急ぎでもありません。利用者がこれから変えるはずの状態を伝えているだけです。ブラウザーはページの求めるとおりに動いています。アラートの領域は文言が変わればすぐに読まれ、利用者が単語を打っている途中かどうかは考慮されません。
二つ目の作り方では、メッセージを役割のない p に書き込むため、エラーが現れても何も読まれないステータスメッセージになり、今度は読まれないという理由で4.1.3を満たしません。達成基準3.3.1の目的も果たせません。3.3.1は、自動的に検出した入力エラーについて、エラーのある項目を特定し、エラーを文字で説明することを求めています。Understandingのページは、その目的を、エラーが起きたことに利用者が気づき、何が誤っているかを判断できるようにすることだとしています。この例では説明はあるものの、欄の下に表示された文字でしかありません。欄と結び付けるものがなく、aria-invalid も aria-describedby もないため、欄は誤りのないものとして読まれます。Understandingのページは、こうしたマークアップを3.3.1の要件とはしていません。とはいえ、それもライブリージョンもなければ、エラーを知る方法は欄の先を1行ずつ読み進めることだけです。Tabキーで問題なく進めたように思えたあとに、そうする人はいません。
この問題に出会うのは、チェックアウトや会員登録のフォームです。スマートフォンで使われることが多く、欄の下のエラーが画面キーボードに隠れることもあります。
10グループ中2グループに影響
- 全盲 (影響あり)
- 弱視 (影響なし)
- 色覚 (影響なし)
- ろう (影響なし)
- 難聴 (影響なし)
- 発話 (影響なし)
- 手の操作 (影響なし)
- 筋力・可動域 (影響なし)
- 認知 (影響あり)
- 光過敏 (影響なし)
- 視覚を使わない スクリーンリーダーの利用者は、アドレスを打ち終える前に、入力した文字に重なってエラーを聞かされます。打ち進めるうちに正しくなったり誤りに戻ったりするたび、また読まれます。欄を離れたときに確かめる場合は何も聞こえず、欄に戻っても、エラーのない欄として読まれます。
- 言語・認知・学習の能力が限られる 1文字目でエラーが現れ、入力のあいだに出たり消えたりすると、まだしていない誤りを指摘されたことになり、入力していた内容から注意がそれてしまいます。
スキャンはフォームを読み込み、ラベルの付いた欄と、その下の空の段落を見つけます。何も入力しないため、エラーが現れる様子は見えず、それがいつ現れるかも分かりません。EaseWebの監査は実際に入力します。メール欄に4文字を打ってTabキーを押し、キーを押しているあいだにフォーム内のライブリージョンへ書き込みがあったときや、Tabキーのあと、どのライブリージョンにも入っていない新しい文字がフォームに現れたときに、人が確かめる項目として挙げます。その文字が欄のエラーかどうか、スクリーンリーダーで何が読まれるかは、人が確かめます。一つ目の作り方では、スキャンには aria-invalid、aria-describedby、role="alert" がそろった、正しく見えるマークアップが見つかることさえあります。React Hook Formのアクセシビリティの例が示すのもこの形で、フォームのエラーをアクセシブルにするよう頼まれたAIアシスタントが、この形を加えることもあります。問題はコードが動くタイミングにあり、スクリーンリーダーを有効にして欄に入力して、初めて分かります。
試してみる
「sam@shop,com」をカンマのまま入力し、Tabキーを押して読み上げを聞いてみましょう
問題1: キーを押すたびにアドレスを確かめ、エラーをアラートで送ります。最初に読まれるのはいつで、入力の途中で何回読まれますか?
問題2: 欄を離れたときにアドレスを確かめます。Tabキーのあと、エラーは読まれますか? Shift + Tabで戻ると、欄はエラーと一緒に読まれますか?
修正を適用します。 「欄を離れたとき」では、入力中は何も読まれず、Tabキーのあとにエラーが一度だけ読まれます。「入力が止まったとき」では、アドレスの途中で1秒手を止めてみてください。
問題あり 修正できますか?
スクリーンリーダーの読み上げ:
(メール欄に入力してください)
修正方法
入力を終えてから確かめ、エラーは一度だけ伝える
キーごとに確かめ、アラートで送るエラー
<label for="email">メールアドレス</label><input type="email" id="email" name="email" required aria-describedby="email-error"><p id="email-error" role="alert"></p>…問題点3点
メッセージの文言は正しく、欄とも結び付いています。問題は、読まれるタイミングです。
- キーを押すたびに確認が動くため、打ち終えていないアドレスの1文字目でエラーが出ます。
- 入力のあいだに正しくなったり誤りに戻ったりするたびに出たり消えたりし、出るたびにまた読まれます。
- アラートとして送られるため、打っている文字に重なって読まれることがあります。
欄を離れたときに確かめ、一度だけ伝える
<label for="email">メールアドレス</label><input type="email" id="email" name="email" required aria-describedby="email-error"><p id="email-error" role="status"></p>…修正の手順4ステップ
- 確認は
changeで動かします。changeは値が変わったあとで欄を離れたときに発生するため、キーを押しているあいだは確かめません。誰も入力していない欄をTabで通り過ぎても、誤りとはされません。 - メッセージの段落に
role="status"を付け、最初から空のままページに置きます。控えめな領域なので、エラーはスクリーンリーダーが今の読み上げ(多くは次の欄の名前)を終えてから一度だけ読まれるはずですが、次の欄の名前に遮られることもあります(「制限」を参照)。 - 欄の
aria-describedbyで段落を指し、同じ処理の中でaria-invalidを設定します。欄に戻ると、無効な入力としてエラーと一緒に読まれます。 - メッセージは変わったときだけ書き込み、
inputではアドレスが正しくなったときに消すだけにします。直せばエラーはすぐに消え、キーを押しているあいだに新しく読まれるものはありません。
これで修正前の二つの問題はどちらも直り、4.1.3と3.3.1を満たします。エラーは、利用者がその欄の入力を終えたあとに、フォーカスを動かさずに一度だけ伝わり、欄とも結び付いたままです。
この方法を選ぶ理由:変化が落ち着いてから、一度だけ伝える
どちらも基準を満たし、利用者の手が止まったときにエラーを一度だけ伝えます。欄を離れたときに確かめる方法は、メールアドレスをはじめ、多くの欄に合います。入力している途中で「アドレスが不完全です」と聞いて助かる人はいません。エラーは、利用者が欄を離れて入力を終えたことを示した時点で伝わります。手が止まったときに確かめる方法は、新しいパスワードや、空いていなければならないユーザー名のように、入力しながら条件に近づけていく欄に合います。欄を離れるまで待たずに、手を止めて様子を確かめるたびに結果が聞こえます。同じメッセージの要素を使い、欄ごとに使い分けるフォームも多くあります。
blur ではなく change を使います。 キーボードやスクリーンリーダーの利用者は、入力を始める前に、何を尋ねられているかを知るためにTabキーでフォームをひととおり移動することがよくあります。blur で確かめると、通り過ぎた欄ごとに確認が動き、まだ何も入力していない必須の欄がすべて誤りとされてしまいます。change は値が変わったときだけ発生します。空のまま残った必須の欄は、フォームを送るときに捉えます。そのときにも同じ確認を行い、まだ誤りのある最初の欄へフォーカスを移してエラーと一緒に読ませるか、エラーの概要を表示します。どの欄が誤りか示さないエラー概要を参照してください。
メッセージは、それだけで意味が通じるようにします。 エラーは自分の欄ではなく、次の欄の名前のあとに読まれます。そのため「形式が正しくありません」ではなく「メールアドレスを…」のように、何についてのエラーかを含めます。文言については直し方がわからないフォームエラーで扱っています。
メッセージの要素は、ページと一緒に描画します。 文言と一緒に現れるステータス領域は、読まれないことがよくあります。コンポーネントのフレームワークでは、エラー用の要素を空のまま描画し、DOMから外さずに置いておきます。メッセージと一緒に要素を加える {#if} や {errors.email && …} の中には置きません。
role="alert" が合う場面。 W3Cの達成方法ARIA19は、フォームを送ったときのエラーを role="alert" に書き込んでいます。利用者は入力を終えたと示しており、先へ進む前に対応が必要です。フォームを入力している途中に見つかったエラーはそうではないため、控えめな領域で伝えます。
フォームのライブラリー。 多くのライブラリーは確認のタイミングを決めており、その設定は見落としがちです。
- React Hook Formは、初期設定では送信時に確かめ、その後は値が変わるたびに確かめます。
onBlurとonTouchedのモードは欄を離れたときに確かめ、onTouchedは最初に欄を離れたあと、値が変わるたびに確かめます。アクセシビリティの例ではメッセージをrole="alert"に入れています。role="status"を使い、要素は描画したままにしてください。 - Formikは値が変わるたびと欄を離れたときに確かめ、チュートリアルでは、一度訪れた欄のエラーだけを表示しています。表示するメッセージの要素は、役割がなく、どこにも結び付いていないただの
divです。 - どのライブラリーでも、付属のコンポーネントがアラートを加えるなら、メッセージの要素は自分で書き、ライブラリーのエラーの状態から欄に
aria-describedbyとaria-invalidを設定します。
使われる前の欄を無効にしません。 空の必須の欄だからといって、最初から aria-invalid="true" を付けて描画しないでください。誰も触れていない欄で「無効な入力」と読まれ、説明するメッセージもありません。aria-invalid は確認の結果から、確認が動いたあとにだけ設定します。
修正にならないもの。 誤りのある欄へフォーカスを戻すと、利用者は欄を離れられず、キーボードの利用者はそこから抜け出せなくなることがあります。role="alert" の代わりに aria-live="assertive" を使っても、同じ失敗です。メッセージを欄と結び付けても、どのライブリージョンにも入れず、利用者が戻ってくるのを当てにするのは、マークアップを整えただけの二つ目の修正前と同じです。戻るよう伝えるものがありません。
文字数カウントも、入力に合わせて変わるメッセージで、考え方は同じです。まったく読まれないか、1文字ごとに読まれてしまう文字数カウンターを参照してください。
デザインの案
エラーは軽やかに見せたまま、言葉にして、ちょうどよいときに伝えられる
欄のエラーの4通りの描き方です。それぞれに誤りを含めて入力し、Tabキーか「次へ」を押してみてください。2つは手を止めたあとに何が誤りかを言葉で伝え、2つは一度も言葉にしません。
デザインファイルで
- ヒントだけの状態、離れたあとにエラーが出た状態、直したあとの状態と、各欄を3通り描く。
- 各エラーの横に、出るタイミングを書く。欄を離れたときか、新しいパスワードのように条件に近づいていく欄なら、1秒手が止まったとき。
- エラーは欄の下に、何を入力すればよいかを言葉で書く。赤い枠、アイコン、揺れは、言葉に添えるだけにする。
- チェックリストには、手が止まったときに読まれる一文を書く。たとえば「3つの条件のうち2つを満たしています」。
- エラーの色の横にコントラスト比を書く。文字は最低4.5:1。
合格
領収書をこのアドレスにお送りします。
エラーに変わるヒントの行 欄の下に、アドレスの用途を伝える灰色のヒント(6.31:1)があります。誤りを含めたまま欄を離れると、同じ行が警告アイコン付きの赤い文字(6.54:1)に変わって何を入力すればよいかを示し、枠は2ピクセルに太くなります。下の内容は動かず、ヒントとエラーはいつも同じ場所に出ます。この行は変わったときに一度読まれ、欄に戻ったときにも欄と一緒に読まれます。基本原則:変化が落ち着いてから、一度だけ伝える
3つの条件をすべて満たしてください
- 12文字以上
- 数字を含む
- 英大文字を含む
入力に合わせてチェックが付くパスワードの条件 新しいパスワードの条件が欄の下に並び、満たした瞬間に、それぞれの空の丸に緑のチェック(6.35:1)が入ります。どこまで満たしたかは、キーを押すたびに目で分かります。一覧の上の「3つの条件のうち2つを満たしています」の行は、1秒手を止めたときにだけ変わり、スクリーンリーダーが読むのはこの行です。基本原則:変化が落ち着いてから、一度だけ伝える
不合格
- 欄の中の×印かチェックだけで、言葉がないWCAG 3.3.1 1文字目から欄の右端に赤い×印が出て、アドレスが正しくなった瞬間に緑のチェックに変わります。素早く、すっきり見えますが、何が誤りで何を入力すればよいかは一度も言葉になりません。しかも×印は、まだ入力途中のアドレスにも出ます。欄の下に言葉を添え、×印は欄を離れてから出してください。
- 揺れて赤くなる欄WCAG 3.3.1 誤りを含めたまま「次へ」を押すと、スマートフォンのロック画面のように欄が左右に揺れ、枠が赤くなります。揺れは変化を示し、0.5秒以内に止まるので、残してかまいません。ただ、何が誤りかは何も伝わらず、動きを減らす設定では赤い枠しか残りません。欄の下に言葉を添えてください。
修正の確認
4項目、マウス不要
確認方法: スクリーンリーダー、キーボード
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。フォームのライブラリーやその設定、欄のコンポーネントを変更した際は、再度確認します。
スクリーンリーダーでの role="alert"、role="status"、aria-describedby、aria-invalid="true"の読まれ方
制限
フォーカスが移るときに書き込まれた控えめなメッセージは、スクリーンリーダーや次の欄の読み上げの長さによって、次の欄の名前のあとに読まれることもあれば、それに遮られることもあります。そのためエラーは欄とも結び付け、戻ったときに読まれるようにしています。このガイドは、ブラウザーの中で確かめる一つの欄を扱っています。メッセージの文言と、欄が誤りであることの示し方は直し方がわからないフォームエラーで、フォームを送ったときのエラーの一覧はどの欄が誤りか示さないエラー概要で、その場で送るフォームの結果は読み上げられないフォームの送信結果で扱っています。実際のフォームを、そのライブラリーやサーバー側の確認も含めて、利用者が使うスクリーンリーダーで確認してください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
EaseWebのサービス
修正した問題を、次のリリースで再発させない
このガイドのような修正方法を、コーディングエージェントが従うルールと、CIのチェックに組み込みます。あわせて定期的に、キーボードとスクリーンリーダーで手動の再テストを行います。