这类问题看似集中在一个 API 或参数上,真正决定可用性的却是状态归属、资源上限和失败后的恢复方式。 DOM 显示变化不等于辅助技术知道上下文变化。弹窗打开要把焦点移入,关闭要回到触发者;路由切换要把焦点送到新页面标题,而不是保留在已移除的侧栏链接。
前端架构的核心不是目录层级,而是状态由谁拥有、事件能否重复执行、旧异步结果如何失效,以及卸载后监听器和资源是否真正归零。
先把实现决策说清楚
落地时要把关键选择变成稳定契约:输入如何校验、状态由谁推进、资源何时释放、旧版本如何降级。只有这样,后续优化才不会改变原有语义。
- 组件打开时选择语义最合理的初始焦点,危险确认不默认聚焦。
- 保存触发元素弱引用,关闭时仅在元素仍可见可用时恢复。
- 异步错误用 live region 宣布,同时把焦点留在可修正字段或错误摘要。
焦点是交互状态的一部分。把移动与恢复写进组件契约并自动测试,才不会在视觉重构后悄悄破坏键盘路径。
最容易漏掉的失败路径
边界条件会把隐藏假设变成真实事故。弱网、刷新、并发和容量上限必须组合测试,因为单独出现时它们往往都能被重试掩盖。
- CSS 隐藏背景但焦点仍能 Tab 进去,用户操作不可见按钮。
- 关闭后强制聚焦已卸载元素抛异常,后续键盘导航失效。
- 每次进度更新都抢焦点,文件传输期间用户无法操作其他控件。
上线前怎样验证
验证时同时观察两端状态、持久化记录和可观测指标。单看某个按钮或一次接口响应,无法证明整个闭环成立。
- 只用键盘完成连接、拒绝、发送、取消和设置,记录任何焦点丢失。
- 在弹窗打开时触发路由切换与异步错误,确认焦点最终位置唯一。
- 使用屏幕阅读器检查标题层级、live region 频率与关闭后的上下文。
最终结果应同时满足正确性、可恢复性和可解释性。任何一项只能依赖刷新页面或工程师猜测,都说明协议闭环仍不完整。