公司动态

金融场景的无障碍设计:关键信息的读屏优先级与错误告知策略

📅 2026/7/22 11:51:37
金融场景的无障碍设计:关键信息的读屏优先级与错误告知策略
金融场景的无障碍设计关键信息的读屏优先级与错误告知策略一、引言当视障用户无法听到自己的持仓亏损时这是一个严重的信息不公平金融产品是高度依赖视觉来传递信息的——红色的亏损、绿色的盈收、K 线的趋势、仪表盘的旋转每一条信息都在假设用户是一个能看清楚的人。但在中国有 1700 万视障人士他们同样需要理财、需要查看账户余额、需要确认交易是否成功。更严重的是金融信息中的关键信息一旦无法被屏幕阅读器正确传达后果远比普通网页严重。比如一次转账操作如果屏幕阅读器将转账金额 5000 元读成了金额 5000漏了转账用户可能无法区分这是一笔收入还是支出。而且在金融场景中这种失误可能导致真实的财产损失。金融无障碍设计的挑战不仅是技术问题更是一个信息优先级的设计问题。一张 K 线图上有几十个信息点——哪些应该被屏幕阅读器读出来按什么顺序用什么样的语言来描述这些问题不能把决定权完全交给浏览器或屏幕阅读器的默认行为。二、底层机制与原理深度剖析关键信息的读屏优先级金融场景应该将信息分为三个优先级P0必须播报账户余额、交易金额、交易状态、风险提示。这些信息必须被屏幕阅读器以最高优先级读出且不能有任何歧义。P1建议播报涨跌幅、收益率、产品到期日。这些信息建议读出但不强制用户可以跳过。P2不应播报纯装饰性元素、背景色、分割线、重复的信息。这些对屏幕阅读器用户来说是噪音。三、生产级代码实现/** * 金融场景无障碍增强组件 * * 核心功能 * 1. 信息优先级播报控制 * 2. 交易错误感知告警 * 3. 数据图表的替代文本生成 */ /** * 紧急信息播报 Hook * * 用于需要立即被屏幕阅读器感知的关键信息 * 如交易成功/失败、风险等级变化等 */ function useUrgentAnnouncement() { const announceRef useRefHTMLDivElement(null); /** * 立即播报一条关键信息 * 使用 aria-liveassertive 确保屏幕阅读器立即中断当前内容进行播报 * * param message 要播报的内容已格式化好的可读文本 * param priority 优先级 */ const announce useCallback(( message: string, priority: critical | warning | info info ) { if (!announceRef.current) return; // 构建带上下文的信息文本 const fullMessage priority critical ? 重要提醒${message} : priority warning ? 温馨提示${message} : message; // 通过修改 aria-label 触发屏幕阅读器重新读取 announceRef.current.setAttribute(aria-label, ); // requestAnimationFrame 确保屏幕阅读器能感知到变化 requestAnimationFrame(() { announceRef.current?.setAttribute(aria-label, fullMessage); }); // 对严重错误增加震动反馈如果设备支持 if (priority critical navigator.vibrate) { navigator.vibrate([200, 100, 200]); } }, []); const AnnouncementRegion useCallback(() ( div ref{announceRef} rolealert aria-liveassertive aria-atomictrue classNamesr-only / ), []); return { announce, AnnouncementRegion }; } /** * 交易错误感知告警组件 * * 设计原则 * 1. 错误必须被屏幕阅读器主动读出 * 2. 错误信息包含原因 建议操作 * 3. 严重错误需要多重感官反馈听觉 触觉 */ const FinancialErrorAlert: React.FC{ error: FinancialError; onRetry?: () void; } ({ error, onRetry }) { const { announce } useUrgentAnnouncement(); useEffect(() { // 当错误出现时自动播报给屏幕阅读器 const errorMessage buildAccessibleErrorMessage(error); const priority error.level critical ? critical : warning; announce(errorMessage, priority); }, [error]); return ( div rolealert aria-live{error.level critical ? assertive : polite} className{financial-alert financial-alert--${error.level}} // 给屏幕阅读器提供完整的错误描述 aria-label{buildAccessibleErrorMessage(error)} {/* 图标给屏幕阅读器提供替代文本 */} span aria-hiddentrue classNamefinancial-alert__icon {error.level critical ? ⛔ : ⚠️} /span {/* 错误标题 */} h4 classNamefinancial-alert__title {error.type transaction_failed ? 交易失败 : error.type insufficient_balance ? 余额不足 : error.type risk_mismatch ? 风险等级不匹配 : 操作异常} /h4 {/* 错误详情 */} p classNamefinancial-alert__description {error.message} /p {/* 操作建议 */} {error.suggestion ( p classNamefinancial-alert__suggestion 建议{error.suggestion} /p )} {/* 重试按钮 */} {onRetry ( button onClick{onRetry} aria-label{重新尝试${error.operation || 操作}} 重试 /button )} /div ); }; /** * 构建屏幕阅读器友好的错误信息 * * 格式[错误级别] [错误类型] [具体原因] [操作建议] * * 例: 交易失败。原因是银行卡余额不足。建议您更换支付方式或联系银行确认余额。 */ function buildAccessibleErrorMessage(error: FinancialError): string { const parts: string[] []; // 错误级别 parts.push(error.level critical ? 交易失败 : 操作提示); // 具体原因 parts.push(原因是${error.message}); // 操作建议 if (error.suggestion) { parts.push(error.suggestion); } return parts.join(。); } /** * 金融数据卡片无障碍增强 * * 确保屏幕阅读器能正确理解金融数据的含义 */ const AccessibleFinanceCard: React.FC{ label: string; // 如当前余额 value: number; // 如12580.50 unit: string; // 如元 change?: number; // 如3.25 changeLabel?: string; // 如较昨日 } ({ label, value, unit, change, changeLabel }) { // 为屏幕阅读器构建完整的可读文本 const accessibleLabel [ label, ${value.toLocaleString(zh-CN)}${unit}, change ! undefined ? ${changeLabel || } ${ change 0 ? 上涨 : change 0 ? 下跌 : 持平 } ${Math.abs(change).toFixed(2)}% : ].filter(Boolean).join(); return ( div classNamefinance-card roleregion aria-label{accessibleLabel} // 使用 aria-describedby 将视觉变化关联到卡片 aria-describedby{card-desc-${label.replace(/\s/g, -)}} {/* 可见的 UI */} span classNamefinance-card__label aria-hiddentrue{label}/span span classNamefinance-card__value aria-hiddentrue {value.toLocaleString(zh-CN, { minimumFractionDigits: 2 })} small{unit}/small /span {change ! undefined ( span className{finance-card__change ${change 0 ? up : change 0 ? down : flat}} aria-hiddentrue {change 0 ? : }{change.toFixed(2)}% /span )} /div ); }; /** 金融错误类型 */ interface FinancialError { type: transaction_failed | insufficient_balance | risk_mismatch | network_error | system_error; level: critical | warning | info; message: string; suggestion?: string; operation?: string; }四、边界分析与架构权衡关键缺点金融数据的语义复杂性。简单的aria-label难以充分描述复杂的金融关系如您的持仓中A 股票占比 30% 但贡献了 60% 的亏损。复杂的数据解读仍然需要人工编写替代文本。屏幕阅读器之间的兼容性。JAWS、NVDA、VoiceOver 对 ARIA 属性的处理存在差异金融产品通常不会做全面的屏幕阅读器兼容测试。实时数据的动态播报。当行情数据每秒变化时屏幕阅读器不断播报会变成噪音需要在频率和信息完整性之间做取舍。安全信息的播报风险。在公共场所使用屏幕阅读器时账户余额、交易金额等敏感信息可能被他人听到需要提供隐私模式。适用边界适用不适用金融监管合规要求内部工具用户可选择使用面向普通消费者的金融产品专业交易员使用的终端交易确认/风险披露场景极高频实时行情数据五、总结金融场景的无障碍设计不是锦上添花的功能而是守住底线的要求。当一个视障用户无法通过屏幕阅读器正确理解自己的账户信息时这不仅仅是体验问题——在某种意义上这是一种隐性歧视。AI 可以在以下方面增强金融无障碍设计自动生成复杂的金融数据描述如持仓分析报告的文字摘要检测页面上缺失的 ARIA 标注为异常事件生成可读的错误说明但 AI 不能替代的一件事是——同理心。真正的无障碍设计需要设计师和开发者成为用户的耳朵去理解当一个视障用户使用你的产品时他真正需要听到的是什么。作者李慕杰Leo / 8limujie一个努力让金融信息能被听见的前端匠人