第17章 人間は、自分の行動に反応を期待する
照明のスイッチを押しても光らなければ、押せていないのか、故障か、遅れているのかを判断できません。Web でも、ボタンを押した後に変化がなければ、利用者はもう一度押し、戻り、諦めるかもしれません。
本章ではフィードバックを、押した瞬間のアニメーションだけでなく、受付、処理中、成功、失敗、回復まで続く状態の情報として見ます。
この章の必修は三つです。
- 操作前から完了後までの状態と遷移を列挙する
- 見える状態、操作可能性、支援技術へ伝わる状態を同期する
- 遅延、失敗、取消、再試行を含む条件で確かめる
判断には八段階を使います。利用者の行為と期待結果を決め、クライアント、通信、サーバー、永続化、別クライアントの状態を列挙します。受付、処理中、確定、失敗、取消、結果不明、回復の遷移を書き、各状態の見える情報、操作可能性、支援技術へ伝わる状態、通知を対応させます。次に重複、順序逆転、再読込、別タブを注入し、複数原因を残します。UI 表示、操作制御、サーバー処理を一軸ずつ変え、完了、重複、データ損失、回復、状態理解、副作用を確かめます。
状態は一列の排他的なラベルではありません。ホバー/フォーカス/アクティブという入力状態、有効/無効という操作可能性、編集中/処理中という処理状態、成功/エラー/不明という結果状態は同時に成立し得ます。
17.1 Switch を押したのに何も起きない
行為の直後に必要なのは派手な動きではなく、入力が受け取られたか、何が変わったかを知る手がかりです。音、抵抗、光、位置、テキスト、振動など複数の経路があります。
「反応がない」を観察語へ変えます。押した瞬間の見た目が変わらない、フォーカスが見えない、送信後もボタンが操作可能、処理中のテキストがない、成功後もデータが変わらない、というように時点と属性を記録します。
17.2 フィードバックとアニメーションは同じではない
アニメーションは変化を時間的につなぐ手段です。フィードバックは、行為を受け取ったこと、処理、結果、次の可能な操作を知らせる役割です。色、テキスト、アイコン、音、振動、フォーカス移動、内容更新でもフィードバックを作れます。
アニメーションがあっても、何を処理し、成功したか分からなければ十分ではありません。アニメーションを止めても意味が伝わるか、prefers-reduced-motion で動きを減らしたときに状態が残るかを確認します。
17.3 ボタンを押す前から完了後まで
通常、ホバー、フォーカス、アクティブは入力との関係を示します。無効、ローディング、成功、エラーはドメイン条件や処理結果とも関係します。同じ平面のスタイル見本として並べるだけでは、どこからどこへ移るかが分かりません。
状態表には、開始条件、利用可能な操作、DOM 属性、見える表現、通知、終了条件、失敗時の遷移を書きます。ホバーがないタッチ、ポインターを使わないキーボード、音声出力も含めます。
17.4 通信遅延の間に何が起きるか
送信と結果の間が延び、画面が変わらないと、利用者が二つの出来事を結び付けにくくなったり、再操作したりする可能性があります。ただし、知覚された因果、再押下、重複リクエスト、重複した業務処理は別の仮説と結果です。遅延だけから順に起きるとは断定しません。
単にボタンを無効にすれば解決とは限りません。何を待っているか、取消せるか、入力データは保たれるか、再試行は同じ処理を重複させないかを設計します。注文や決済では、クライアント側のボタン制御だけでなく、サーバー側の冪等性や処理 ID も必要です。
通信を高速なまま確認せず、遅延、オフライン、タイムアウト、応答順序の逆転、サーバー成功後に応答だけ失われる条件を試します。
応答が失われた場合、クライアントからは成功か失敗か分からない結果不明になります。再試行で新しい処理を始めるのか、同じ処理 ID を再照会するのかを分けます。検索の再実行と決済の再実行では影響が違います。
17.5 ローディング表示は何を伝えるか
ローディング表示には、少なくとも開始、継続中、進行量、残り見込み、取消可能性があります。スピナーは処理中を示せても、何割終わったかは示しません。全体量と完了量を測れるなら進捗を示せますが、架空の 99%を長く見せると予測を壊します。
スケルトン UI は内容の概形を先に示す手段です。処理完了の保証ではなく、レイアウトシフトを抑える設計とも関係します。実際の内容と異なる骨格、終わらない反復、複数領域の別々の待機に注意します。
F05 は同じタスクの因果比較ではなく、アップロードとページ読込という異なる待機タスクに応じた手段の分類です。アップロード内でスピナーと実測進捗を比べる系列と、ページ読込で全体スピナーと領域別スケルトンを比べる系列を接続して効果を推定しません。
17.6 Optimistic UI の期待と回復
Optimistic UI は、サーバーの成功確定前に手元の表示を成功状態へ進める方式です。即座に見えても、成功した事実を早く作る技法ではありません。
失敗したら、元へ戻す、再試行を促す、未同期として残す、利用者に選ばせる等の回復が必要です。金銭、在庫、権限、共同編集の競合など、誤った成功表示の影響が大きい操作には慎重さが要ります。
操作 ID、手元の仮状態、サーバー版、更新番号を対応させます。古い失敗応答で新しい成功を巻き戻さず、直後の別操作、再読込、別タブ、オフライン時の待ち行列、権限変更と整合させます。巻き戻し、未同期保持、再試行の選択は、業務上のリスク、回復可能性、競合解決方法で決めます。
比較するときは、成功率だけでなく、失敗が発覚するまでの時間、データ損失、重複、回復完了、利用者が状態を正しく説明できるかを見ます。
17.7 見える状態と支援技術へ伝わる状態
色やスピナーが変わっても、支援技術へ状態が伝わるとは限りません。WCAG 2.2 の Status Messages は、フォーカスを移さずに提示される操作結果、待機、進行、エラー等が、役割やプロパティを通じて判定できることを求めます。
すべての更新を alert にすると割込みが増えます。通常の結果には文脈に応じて status や output、緊急で時間的に重要な情報には alert を検討します。更新先のコンテナは更新前から存在させる必要がある場合があり、ブラウザ/OS/スクリーンリーダーの組合せで確認します。
ネイティブの disabled はフォーカスや送信にも影響します。無効理由を知る経路が失われないかを確認します。見た目、操作可能性、DOM 状態、アクセシビリティツリー、読み上げを別々に監査します。
17.8 状態表を作り、欠けを探す
画面のスクリーンショット一枚では、待機や失敗を見落とします。商品登録フォームを例に、状態表を作ります。
| 状態 | きっかけ | 見える表示 | 操作 | 支援技術へ伝わる状態 | 次 |
|---|---|---|---|---|---|
| 編集中 | 入力 | 入力値 | 編集・送信 | value | 送信中 |
| 送信中 | 送信 | 「保存中」 | 取消の可否 | aria-busy 等を文脈で検討 | 成功/失敗 |
| 成功 | 2xx+整合確認 | 「保存しました」 | 次へ | status message | 編集中 |
| 入力エラー | 入力検証 | 対象と直し方 | 修正 | native validity/関連付け | 編集中 |
| 未送信 | オフライン等でリクエスト未到達 | 「送信できませんでした」 | 編集・再送 | request state | 送信中/編集中 |
| 失敗確定 | サーバー拒否 | 「保存できませんでした」 | 修正・再試行 | operation failed | 送信中/編集中 |
| 応答タイムアウト | 所定時間に応答なし | 「結果を確認しています」 | 再照会 | request timed out | 結果不明 |
| 取消要求中 | Cancel | 「取消中」 | 二重取消を防ぐ | operation ID | 取消確定/結果不明 |
| 結果不明 | 応答消失 | 「結果を確認中」 | 再照会 | 同じ操作 ID | 成功/失敗/サポート |
| 部分成功 | 複数処理の一部完了 | 完了と未完了 | 未完了だけ再試行 | item 別 state | 完了/結果不明 |
| 古い応答・競合 | 応答逆転/別クライアント更新 | 現在版と競合 | 再読込・選択 | バージョン | 編集中/解決済み |
問い
- 操作前、受付直後、処理中、成功、失敗、回復に何がありますか。
- 各状態へ入る Trigger と出る条件は何ですか。
- 利用者は今何が起き、次に何ができると判断できますか。
- ポインター、キーボード、タッチ、スクリーンリーダーで情報は一致しますか。
- 遅延、オフライン、二重送信、応答逆転で何が起きますか。
- 何を観察し、どの仮説を反証しますか。
答えの例
送信直後もラベルが「保存」のままでボタンを何度でも押せます。受付状態が見えず、二重送信の可能性があります。ただし原因はフィードバック不足だけでなく、クリック処理の未接続、通信開始前のメインスレッド停止、支援技術だけに通知がある場合もあります。
まずイベント、リクエスト ID、ボタン状態、DOM、アクセシビリティツリー、サーバーログを同じ時刻軸で確認します。ボタン文言だけを「保存中」へ変える案、重複操作をサーバーで同一処理へ束ねる案を別々に試します。タスク開始数を分母に二重送信率、完了率、回復率を記録し、キーボードと遅延条件でも確かめます。
別の答え方
処理が手元で瞬時なら、ローディングを挟むことでかえってちらつくかもしれません。結果データが即時に変わり、その変化を理解できるなら、別のフィードバックがすでに成立している可能性があります。
よくある考え方
スピナーを付ければ分かりやすくなります。
注意点
受付、進行、完了、失敗、回復のどれをスピナーが伝えるのかがありません。動きは意味、操作制御、重複防止、支援技術への通知を自動では満たしません。
さらに二つの答えの例
注文の応答が失われた: 画面はタイムアウトですが、サーバーには注文があるかもしれません。通信失敗、処理失敗、応答だけの消失、古い画面を仮説にし、処理 ID でサーバー状態を再照会します。「もう一度注文」を「注文状況を確認」へ変える比較と、サーバーの冪等性だけを変える試験は分けます。注入した応答消失件数を分母に結果確認率、重複業務処理率、回復完了率を記録します。サーバーが一件も受け付けていなければ応答消失仮説は反証されます。
- 別解: 検索のように再実行の影響が小さいタスクなら、新しい処理として再試行する方が早い場合があります。
- よくある考え方: Timeout なら失敗なので、同じ注文をもう一度送ります。
- 注意点: リクエストのタイムアウトは、所定時間に応答がなかったという通信上の観察で、業務処理の失敗確定ではありません。再照会と新規再試行を分けます。
お気に入りの仮更新が失敗した: 手元では選択済み、サーバーでは未選択、別タブは古い状態です。拒否、古い応答、バージョン競合、オフライン時の待ち行列を仮説にします。操作 ID、クライアント版、サーバー版、タブ間同期を監査し、まず未同期ラベルだけを加えます。注入した拒否数を分母に状態説明正答、回復、直後の別操作が失われた件数を測ります。再読込後も全クライアントが同じ確定版を示せば不整合仮説は弱まります。
- 別解: 失敗をすぐ巻き戻さず未同期として残し、接続回復後に再送する方が意図を保てる場合があります。
- よくある考え方: 失敗したら必ず元へ戻せば安全です。
- 注意点: 元へ戻す処理が、その後の別操作や新しいサーバー版を上書きすることがあります。処理の版を比較します。
見える成功が読み上げられない: 保存済みテキストは見えますが、アクセシビリティツリーにステータスがありません。更新コンテナの役割不足、更新時点、支援技術の組合せ、通知過多を仮説にします。まず適切なステータスの意味だけを加え、対象環境ごとに通知検出数/状態更新数とタスク中の理解を別に記録します。役割がツリーへ出ても通知されなければ、仕様適合だけで告知成功を証明できません。
- 別解: エラー修正のために操作を求める場合は、ステータス通知だけでなくエラー概要やフォーカス設計が必要かもしれません。
- よくある考え方:
role="status"を付ければ全員に必ず伝わります。 - 注意点: 仕様上の役割、特定環境での通知、利用者の検出と理解は別の証拠です。
共通 Rubric
各回答で、状態所有者、受付から回復までの遷移、最低二つの原因、クライアント/サーバー監査、一軸変更、分母付き指標、副作用、反証条件を確認します。未測定は空欄にし、推測で埋めません。
セルフチェック
- 操作前から回復までの状態と遷移を列挙できる
- フィードバックとアニメーション、視覚状態とプログラム上の状態を分けられる
- 遅延・失敗・入力方法を変え、分母付き指標と反証条件を示せる
- 結果不明、取消、競合、古い応答から安全に回復する経路を示せる
参考
- ISO 9241-110:2020 — Self-descriptiveness を、状態と利用 Context から読みます。
- WCAG 2.2, SC 4.1.3 Status Messages — フォーカスを移さない状態更新の要件です。
- WAI-ARIA 1.2 —
status、alert、aria-busyの規範的定義です。 - ARIA Authoring Practices Guide, Alert pattern — Informative な実装例であり、規格そのものではありません。
- HTML Living Standard —
button、disabled、output、progressを確認します。