エラーメッセージとマイクロコピーのアクセシビリティ完全ガイド:迷わせない言葉、疲れさせない通知、確実に直せる導線
概要サマリー(先に要点)
- “何が問題か/どこで起きたか/どう直すか” を1メッセージで完結させ、色だけに頼らない重複伝達(テキスト+アイコン+コントラスト)を行います。
- 要約エリア+各項目の個別エラーの二段構え、**
role="alert"
とrole="status"
の使い分け、フォーカス移動で修正を最短化。- 予防的マイクロコピー(例・制約・ヒント)でエラー発生を最小化し、リアルタイム検証は控えめに。
- 非同期/ネットワーク/権限/競合など“フォーム外”の失敗も含め、回復手段(再試行・下書き保存・連絡先)を明示。
- 実装スニペット(HTML/ARIA/CSS/JS)、文例テンプレ、5分スモークテスト、組織の言語スタイルガイドの作り方まで収録。
対象読者(具体):プロダクトマネージャー、UI/UXデザイナー、テクニカルライター、フロントエンドエンジニア、QA/CS、ドキュメント担当
アクセシビリティレベル:WCAG 2.1 AA 準拠を基準(可能箇所は AAA を志向)。1.3.1/1.4.1/1.4.3/1.4.11/2.1.1/2.2.2/2.4.3/2.4.6/2.4.7/3.3.x/4.1.2 を中心に対応
1. はじめに:エラーは“叱る”ためではなく“助ける”ためにあるの
エラーメッセージは、ユーザーの“つまずき”を次の一歩へと導く小さな手です。
怒ったような赤文字や専門用語の羅列は、認知負荷と不安を高め、離脱の引き金になります。
わたしたちが目指すのは、落ち着いた言葉と確実な修正手順、そして誰の状況でも読める・気づける表現。
アクセシビリティは、視覚・聴覚・運動・認知の多様性や、片手操作・騒音・低速回線・小画面といった“環境の揺れ”にも効きます。
このガイドでは、設計→文案→実装→検証→運用の順で、現場でそのまま使える型をご紹介しますね。
2. 大原則:3点セットで“即、直せる”
2.1 メッセージの黄金比(What / Where / How)
- What(何が問題?):具体的事実を短く。「郵便番号は7桁の数字ではありません」。
- Where(どこで?):該当フィールドをテキストで特定。「郵便番号」。
- How(どう直す?):修正方法を一文で。「ハイフンなしの7桁で入力してください(例:1000001)」。
例(良い):「郵便番号が未入力です。7桁の数字をハイフンなしで入力してください(例:1000001)。」
2.2 重複伝達(色だけに頼らない)
- テキスト+アイコン+コントラスト(本文4.5:1/非テキスト3:1)。
- 形・位置でも伝達(入力欄の境界強調、フォーム上部の要約)。
- 音や振動は任意、ミュートでも成立する表現を基本に。
2.3 2段構え(要約+個別)
- ページ上部にエラー要約(各項目へのアンカーリンク)。
- 各フィールド横に個別メッセージ。視線の往復を最小化。
3. 予防設計:そもそもエラーを起こさない
- 可視ラベルと例示を近接配置(
aria-describedby
で結び、読み上げにも露出)。 - 型(type)・
autocomplete
・inputmode
で“打たせない”。 - 制約は事前に:桁数・形式・選択条件はヒントで先出し。
- 分割入力(住所・電話)は自然な順序に。
- リアルタイム検証はフォーカスアウトまたは入力の一時停止後(300–600ms)。途中の赤点灯は疲労の原因ですわ。
サンプル(ヒント+連係)
<div class="field">
<label for="zip">郵便番号 <span aria-hidden="true">*</span></label>
<input id="zip" name="zip" inputmode="numeric" autocomplete="postal-code"
aria-describedby="zip-hint zip-err" required>
<small id="zip-hint">7桁の数字。ハイフン不要(例:1000001)</small>
<span id="zip-err" class="error" role="alert" hidden>7桁の数字で入力してください。</span>
</div>
4. エラーの視覚設計:見落とさせない、騒がせすぎない
- 色:本文4.5:1、枠線やアイコンは3:1以上。
- アイコン:形状で意味がわかるもの(例:エラー▲/注意!/成功✔)。
- フォーカス:
:focus-visible
の太い輪郭+オフセットで所在を明確に。 - 密度:同時に複数の赤が灯ると負荷大。要約で集約→個別へ誘導。
- モーション:揺らす・点滅は原則禁止。色+文で落ち着いて伝達。
.error { color:#b00020; }
input[aria-invalid="true"] { border:2px solid #c62828; box-shadow:0 0 0 3px rgba(198,40,40,.18); }
:focus-visible { outline:3px solid #ff9900; outline-offset:3px; }
5. ARIAとライブリージョン:通知の“聞こえ方”を整える
role="alert"
:即時・割り込み。エラーや重要失敗に限定。role="status"
:静かな通知(保存完了・下書き保存など)。aria-live="polite"
:自動更新の“控えめ”実況。aria-atomic="true"
:部分更新でも全文読み直すべき時に。
サンプル(要約エラー+フォーカス受け皿)
<div id="error-summary" role="alert" aria-labelledby="err-title" hidden tabindex="-1">
<h2 id="err-title">入力内容を確認してください</h2>
<ul>
<li><a href="#zip">郵便番号:7桁の数字で入力</a></li>
<li><a href="#email">メール:形式が正しくありません</a></li>
</ul>
</div>
<script>
function showSummary(){ const sum = document.getElementById('error-summary'); sum.hidden = false; sum.focus(); }
</script>
使い分けのコツ:
- フィールドエラー:フィールド脇に
role="alert"
を置くと確実に気づけます。- 保存成功:
role="status"
で“静かに”知らせます。- ネットワーク切断:
alert
+回復手段(再試行/オフライン下書き)を同時に提示。
6. 文案の作り方:やさしく、短く、具体的に
6.1 文体の原則
- 主体はユーザー:「あなた」ではなく項目名を主語に(「郵便番号が未入力です」)。
- 禁止ではなく提案:「入力できません」は避け、「7桁の数字で入力してください」と行動を示す。
- 専門用語の翻訳:タイムアウト→「一定時間操作がなかったため、セキュリティ上ログアウトしました」。
- 数字で具体化:「しばらく」より「2分」。
6.2 よく使うテンプレ(日本語)
- 未入力:「{項目}が未入力です。{要件}を入力してください。」
- 形式不一致:「{項目}の形式が正しくありません。{例}の形式で入力してください。」
- 範囲外:「{項目}は{最小}〜{最大}{単位}で入力してください。」
- 重複:「この{項目}はすでに使用されています。別の{項目}をご検討ください。」
- ネットワーク:「通信に失敗しました。接続を確認して再試行してください。下書きは保存済みです。」
- 権限/セキュリティ:「この操作を行う権限がありません。管理者に連絡してください。」
6.3 “悪い例→良い例”
- 悪:「無効な入力です」 → 良:「電話番号はハイフンなしの10〜11桁で入力してください(例:0312345678)。」
- 悪:「エラーが発生しました(-1001)」 → 良:「通信がタイムアウトしました。接続を確認して再試行してください。」
7. 非同期・サーバーサイドの失敗:フォーム外の“現実”に備える
7.1 代表的なシナリオ
- ネットワーク不安定:送信失敗・読み込み中断。
- サーバーエラー:5xx、メンテナンス。
- 競合:他デバイスでの同時編集。
- 権限・認可:トークン失効、アクセス拒否。
- ファイル:サイズ上限・拡張子・ウイルス検出。
7.2 回復戦略
- 再試行(ボタン+ショートカット)を明示し、何度試せるかを一言で。
- 下書き保存と自動復元を提供。
- 問い合わせ窓口(メール・電話・テキスト中継)をテキストで提示。
- 状態の可視化:
role="status"
で「送信中…」「保存しました」を短く。
サンプル(再試行UI)
<div role="alert">
保存に失敗しました。ネットワークを確認して<a href="#" id="retry">再試行</a>してください。下書きは保持されています。
</div>
<script>
document.getElementById('retry').addEventListener('click', e => { e.preventDefault(); saveDraftAgain(); });
</script>
8. 認知負荷を下げる:順序、段階化、選択肢の“絞り込み”
- 段階的開示:一度に出しすぎない(アコーディオン・ステップ)。
- 選択肢は5〜7個程度に。多い場合は検索つきコンボへ。
- 例示は具体的に(“東京→千代田区→1-1-1”のように階段)。
- 長文の要約:先頭に「要点:」を置く。
- アイコンは補助:必ずテキストが主役。
9. 多言語・読み上げ・音声操作:言語と入出力の多様性に寄り添う
lang
属性をページと一部の外来語に正確に付与。- 可視文言=アクセシブルネーム(2.5.3)。アイコンボタンには同じ語を。
- 機械翻訳でも崩れない短文・構文に(主語・述語を簡潔に)。
- 数字・日付・通貨はローカライズ(例:YYYY-MM-DD を明記)。
- 音声操作のため、ボタン名・リンク文を行為中心に(「削除」「送信」「やり直す」)。
10. コード雛形:フォーム+要約エラー+個別エラー(コピペOK)
<form id="f" novalidate aria-describedby="note">
<p id="note">*は必須。入力は2分ほどです。</p>
<div id="summary" role="alert" aria-labelledby="summary-title" hidden tabindex="-1">
<h2 id="summary-title">入力内容を確認してください</h2>
<ul id="summary-list"></ul>
</div>
<div class="field">
<label for="name">氏名 <span aria-hidden="true">*</span></label>
<input id="name" name="name" required aria-describedby="name-err">
<span id="name-err" class="error" role="alert" hidden>氏名は必須です。</span>
</div>
<div class="field">
<label for="email">メール <span aria-hidden="true">*</span></label>
<input id="email" name="email" type="email" required aria-describedby="email-hint email-err">
<small id="email-hint">例:user@example.com</small>
<span id="email-err" class="error" role="alert" hidden>メールの形式で入力してください。</span>
</div>
<button id="send">送信</button>
<div id="status" role="status" aria-atomic="true" class="sr-only"></div>
</form>
<script>
const fields = [
{ id:'name', err:'name-err', check: el => el.value.trim().length>0, msg:'氏名は必須です。' },
{ id:'email', err:'email-err', check: el => el.validity.valid, msg:'メールの形式で入力してください。' }
];
document.getElementById('f').addEventListener('submit', e=>{
e.preventDefault();
const list = document.getElementById('summary-list');
const sum = document.getElementById('summary');
list.innerHTML = '';
let firstBad = null;
fields.forEach(f=>{
const el = document.getElementById(f.id);
const ok = f.check(el);
const err = document.getElementById(f.err);
el.setAttribute('aria-invalid', String(!ok));
err.hidden = ok;
if(!ok){
if(!firstBad) firstBad = el;
list.insertAdjacentHTML('beforeend', `<li><a href="#${f.id}">${f.msg}</a></li>`);
}
});
if(firstBad){
sum.hidden = false; sum.focus();
list.querySelectorAll('a').forEach(a=> a.addEventListener('click', ()=>document.getElementById(a.getAttribute('href').slice(1)).focus()));
return;
}
const st = document.getElementById('status');
st.textContent = '送信中です…';
document.getElementById('send').disabled = true;
setTimeout(()=>{ // 擬似送信
st.textContent = '送信が完了しました。ありがとうございました。';
document.getElementById('send').disabled = false;
e.target.reset();
}, 1000);
});
</script>
11. “通知”のアクセシビリティ:トースト・バナー・インラインの使い分け
- トースト:短命・軽量な成功通知(保存完了など)。履歴を持てると安心。
- バナー:ページ上部で広域の警告(システム障害・メンテ情報)。
- インライン:特定エリアの結果(フィルタのヒット数・フォームの個別エラー)。
原則
- 自動で消える通知は読み切れる時間(3–5秒+フォーカス時は保持)。
- 一時停止/再開の制御があると親切。
role="status"
を基本、重要度が高いもののみalert
。
12. 失敗しないレビュー観点(デザイン/文案/実装 共通)
- 観点:What/Where/How が1メッセージに入っている?
- 重複伝達(テキスト+色+アイコン)で色依存していない?
- 可視ラベル=アクセシブルネーム(2.5.3)になっている?
- 要約エラー→個別エラーの導線があり、キーボードで往復できる?
- フォーカスは見失わない?
:focus-visible
が十分太い? - ライブリージョンの使い分けは適切?(
alert
乱用していない) - リアルタイム検証は控えめで、入力途中に赤が点かない?
- ネットワーク失敗に再試行・下書き・連絡先がある?
- モバイル(320px)で崩れず、ターゲットサイズ44–48px?
- 多言語でも破綻しない短文構文?固有名詞・単位・日付は一貫?
13. 5分スモークテスト:毎リリースに回せる最小儀式
- Tabだけで入力→送信→要約→個別へジャンプ→修正→再送信が完了。
- スクリーンリーダー(NVDA/VoiceOver)で、エラー発生時に読み上げが即時に行われる。
- 色をグレースケールにしても、テキストとアイコンで意味が変わらない。
- オフラインにして送信→再試行が提示され、下書きが残る。
- 文字拡大(150%)でも折返し破綻なし、重要情報が折りたたまれない。
14. ケーススタディ:離脱率を下げた“3つの変更”
Before
- プレースホルダーのみでラベル無し。
- 入力途中で即赤エラー・常時トースト。
- 送信失敗は「Error -1001」のみ。
After
- 可視ラベル+例示を近接、
aria-describedby
で連係。 - リアルタイム検証はフォーカスアウト時へ変更、要約+個別の二段構えに。
- ネットワーク失敗に再試行ボタンと下書き保存を追加。
結果:フォーム完了率 +18%、エラー由来のCS問い合わせ −37%、送信失敗時の離脱 −52%。
15. よくある落とし穴と回避策
落とし穴 | 何が起きる? | 回避策 |
---|---|---|
「無効です」だけの曖昧文 | 直せない・不安 | What/Where/How の三点セット |
色だけの強調 | 見落とし・誤認 | テキスト+アイコン+コントラスト |
フィールド毎にrole="alert" 乱立 |
騒がしい・読み上げ渋滞 | 重要だけalert 、他はstatus |
入力途中の赤連発 | 認知負荷↑・離脱 | フォーカスアウト時/遅延検証 |
要約なし | どこを直すか迷子 | 要約にアンカー→個別へ |
専門語・略語の濫用 | 意味不明 | 平易化+注釈(abbr 等) |
自動で消える通知 | 読み逃し | 一時停止/履歴/フォーカス保持 |
エラー番号のみ | CS負担↑ | 人間語+番号(開示は末尾) |
16. 組織導入:言語スタイルガイドとデザインシステム
- 言語スタイルガイド
- 人称・敬体、「〜してください」統一。
- 禁止語(抽象語・脅し文句)と推奨表現の対照表。
- テンプレ(未入力/形式/範囲/重複/権限/ネットワーク)。
- デザインシステム
- コンポーネント(アラート/トースト/バナー/エラーフィールド)の名前・役割・値(NRV)を明文化。
- 色・コントラスト・アイコンの最小比、
:focus-visible
の太さ。 - ライブリージョンの運用規約(
alert
の濫用防止)。
- 運用
- PRテンプレにa11yチェック項目を組み込み、自動検査+5分スモークを定例化。
- CSの問い合わせログを言い回しの改善へ反映。
17. 誰がどう助かる?(具体的インパクト)
- 視覚に多様性のある方:色だけに頼らない重複伝達/高コントラストで見落としが減少。
- スクリーンリーダー利用者:
alert
/status
の適切な通知と要約→個別の導線で修正が短時間に。 - 認知・学習特性の多様な方:短文・具体・段階化で負荷が低減。
- モバイル・片手操作:ターゲットサイズ確保・リアルタイム検証の抑制で誤タップ・誤判定が減少。
- 回線が不安定な環境:再試行/下書き保存で作業の中断を回避。
- CS・運用側:問い合わせの定型化・減少、対応の平均時間短縮。
18. アクセシビリティレベルと到達点
- WCAG 2.1 AA 主対応
- 1.3.1 情報及び関係性(要約+個別、関連付け)
- 1.4.1 色の使用(色依存の回避/重複伝達)
- 1.4.3 / 1.4.11 コントラスト(テキスト/非テキスト)
- 2.1.1 キーボード(要約→個別への移動)
- 2.2.2 一時停止・停止・非表示(通知の制御)
- 2.4.3 / 2.4.6 / 2.4.7 フォーカス順序・ラベル・フォーカス可視
- 3.3.1 / 3.3.2 / 3.3.3 エラーの特定・ラベルまたは説明・エラーの提案
- 4.1.2 名前・役割・値(
alert
/status
/aria-invalid
等)
- AAAでの発展(推奨)
- 1.2.8(メディアの代替:トラブルシュート動画にトランスクリプト)
- 1.4.6(コントラスト強化)
- 3.3.6(エラーの予防:重要取引の確認ダイアログ強化)
19. まとめ:やさしい言葉は、だれの心にも届く
- What/Where/How の三点セットで“すぐ直せる”メッセージに。
- 要約+個別とフォーカス移動で修正導線を最短化。
- 重複伝達(テキスト+アイコン+コントラスト)で色依存を脱却。
- リアルタイム検証は控えめに、予防的マイクロコピーでエラーを減らす。
alert
/status
の使い分けと通知の静けさを守る。- 再試行・下書き・連絡先など、回復手段を必ず添える。
- 言語スタイルガイドとデザインシステムで、チームの言葉とふるまいをそろえる。
エラーメッセージは、叱責ではなく伴走です。
あなたのプロダクトが、つまずいた瞬間にこそやさしく確かな手を差し伸べられるよう、わたしも心を込めてお手伝いしますね。