用途
本技能用于指导设计界面中的通知与恢复机制。当发生成功、失败或介于两者之间的任何变化时,用户必须知晓;当出现问题时,用户必须始终有前进的路径。资料强调:没有恢复操作的通知只是一句道歉。
模式选择
资料给出了一张模式选择表,按场景选择不同模式:
- Toast:用户操作的瞬时结果(已保存、已发送、已删除),自动消失 4–6 秒,可手动关闭。
- 内联错误(Inline error):字段级校验、表单错误,纠正后清除。
- 警告横幅(Alert banner):影响当前上下文的持续性问题,手动关闭或状态解决。
- 模态框/对话框(Modal / dialog):需要先做决定才能继续的阻塞性错误,需要用户操作。
- 空状态(Empty state):尚无数据,引导用户完成第一个操作,被第一个条目替换。
- 骨架屏/加载(Skeleton / loading):异步内容等待中,被内容替换。
- 就地确认(In-place confirmation):内联编辑已保存、行已更新、条目已切换,2–3 秒后自动清除。
Toast 通知
Toast 用于确认后台操作已完成,出现时不打断用户流程。
- 位置:底部居中或底部右侧。绝不要顶部居中——它会与页面内容和导航竞争。
- 时长:信息类 4–6 秒。错误应持续到被关闭——用户需要时间阅读并采取行动。
- 结构:[图标] 消息文本 [操作] [×]。图标按颜色编码(绿色 ✓ 成功、红色 ✗ 错误、橙色 ⚠ 警告、蓝色 ℹ 信息);消息一句话、平实语言;操作可选,最多一个(如“撤销”“重试”“查看”);关闭按钮在错误时始终存在,成功时可选。
- 示例:✓“Changes saved.”;✓“Message sent. [Undo]”;✗“Could not save. Check your connection. [Retry]” ← 持续到被关闭。
- 绝不要同时显示多个 Toast。应排队,一次显示一个。
内联错误
内联错误出现在引发错误的元素旁边,是最具上下文和可操作性的错误反馈形式。
表单校验:
- 在失焦(离开字段)时校验,而不是每次按键——按键校验太嘈杂。
- 提交时校验整个表单。
- 错误消息直接显示在字段下方,红色,带图标。
- 字段边框变为 --color-error。
- 错误消息通过 aria-describedby 关联,供屏幕阅读器使用。
示例代码: <label for="email">Email</label> <input id="email" aria-describedby="email-error" aria-invalid="true"> <p id="email-error" role="alert">Enter a valid email address.</p>
就地编辑:
- 当字段被内联编辑(表格单元格、卡片标题)时,在字段旁显示保存/取消控件。
- 保存时:短暂的成功指示(“✓ Saved”),2 秒后淡出——不要跳转离开。
- 出错时:字段下方显示内联错误消息,并提供重试选项。
- 取消时:立即恢复原值。
警告横幅
横幅是持续性的——在条件解决或用户关闭前一直存在。
适用场景:服务降级(“部分功能暂时不可用”)、需要操作的账户问题(“你的订阅将在 3 天后到期。[续订]”)、持续的同步错误(“更改未保存。[重试]”)、与当前页面相关的重要公告。
- 位置:受影响区域的顶部,除非问题确实是全局的,否则不要放在整个页面顶部。
- 结构:[图标] [消息——描述问题及其范围] [操作] [×]。
- 每个区域一次只显示一个横幅——多个同时出现会造成警报疲劳。
- 除非条件具有阻塞性,否则可关闭。
- 颜色遵循状态颜色惯例:红(错误)、橙(警告)、蓝(信息)、绿(成功/已解决)。
恢复模式
每个错误状态都必须有前进路径。设计错误消息的同时就要设计恢复操作。
重试(Retry):
- 用于瞬时故障(网络、超时、速率限制)。
- 示例:“Could not load results.” [Try again]。
- 重试按钮触发同一操作。
- 3 次重试失败后升级:“Still having trouble? [Contact support]”。
- 重试期间显示加载指示器——不要让用户多次点击。
撤销(Undo):
- 用于破坏性或不可逆操作(删除、归档、发送)。
- 示例:“Message sent. [Undo] ×”。
- 撤销窗口:5–10 秒。Toast 在此期间持续。
- 窗口关闭后,操作即为最终结果。
- 对于低风险操作,撤销优于确认对话框——更快、干扰更小。
自动保存与草稿恢复:
- 用于长表单输入(表单、文档、编辑器)。
- 每 30–60 秒静默自动保存。
- 保存失败时:“Autosave failed — your changes are stored locally. [Retry save]”。
- 崩溃或关闭后返回时:“You have unsaved changes from [time]. [Restore] [Discard]”。
优雅降级:
- 当某功能失败但产品其余部分仍可用时:仅对失败区域显示错误状态——不要清空整个页面。
- 提供回退:“Could not load recommendations. [Browse all products →]”。
- 静默记录错误;只向用户展示其需要知道的内容。
加载与骨架状态
加载不是错误,但也是需要设计的状态。
- 内容密集型页面使用骨架屏——数据加载时显示布局形状。
- 定向异步操作(按钮加载、内联刷新)使用加载指示器。
- 已知时长的长操作(文件上传、多步处理)使用进度条。
- 加载时绝不要显示空白屏幕——始终显示一些内容。
- 相比加载指示器,骨架屏能减少感知等待时间。骨架形状要与实际内容布局匹配。
通知中心
Toast 和横幅是瞬时的;通知中心是用户查看和控制接收内容的持久场所。两点使其有效:
易于到达,易于控制。用户必须几乎无需挖掘就能到达通知偏好(铃铛图标 → 中心 → 设置)。控制模型保持粗粒度——最多 1 到 3 个类别,每个类别有简单级别:关闭(0)——该类别全部不接收;最小——仅重要项;全部/细粒度——所有内容。不要构建一堵逐事件开关的墙。两个真实需求占主导:静默一切,或保留一两个类别。直接为这些设计——一个醒目的“全部静音”/“全部标为已读”加上 1–3 个类别开关。
尽量减少阅读。中心是被扫视的,不是被阅读的。按类别分组,每个条目以可识别的图标和实体/操作开头(而不是一段文字),清晰显示未读状态,并允许一键清空整个列表。阅读就是时间——一个要求仔细阅读的通知中心违背了其目的。
通知无障碍
- 错误使用 role="alert"——屏幕阅读器立即播报。
- 状态更新使用 role="status"——礼貌播报(在当前语音之后)。
- Toast 必须可通过键盘访问——不要在关闭按钮上使用 pointer-events: none。
- 自动消失的 Toast 必须有足够时长(偏好减少动效的用户可能需要更多时间阅读)。
示例代码: <!-- Error: immediate announcement --> <div role="alert">Could not save. Check your connection.</div>
<!-- Status: polite announcement --> <div role="status" aria-live="polite">Changes saved.</div>
审查清单
- 每个错误是否都有恢复操作(重试、撤销、联系支持)?
- Toast 是否对成功自动消失、对错误持续显示?
- 是否从不同时显示多个 Toast?
- 内联错误是否放在字段旁边,而不是表单顶部?
- 表单错误是否通过 aria-describedby 关联到其输入?
- 警告横幅是否出现在受影响区域的顶部,而不是总是全页?
- 长表单输入是否有自动保存或草稿恢复?
- 加载状态是否对内容使用骨架屏、对定向操作使用加载指示器?
- 错误是否通过 role="alert" 播报、状态更新是否通过 role="status" 播报?