从删除注释按钮看Thorium Reader无障碍设计:3大痛点与优化方案

从删除注释按钮看Thorium Reader无障碍设计:3大痛点与优化方案

无障碍设计现状:删除注释功能的隐藏障碍

当视障用户通过屏幕阅读器操作Thorium Reader的注释删除功能时,会遭遇一系列"隐形障碍"。这些障碍并非功能缺陷,而是设计中对无障碍标准的忽视。通过分析src/renderer/reader/components/ReaderMenu.tsx核心代码,我们发现当前实现存在三大关键问题:

1. 操作链路的信息断层

删除注释的触发按钮(AlertDialog.Trigger)虽设置了基础aria-label,但缺乏状态变化反馈:

<AlertDialog.Trigger 
  className={stylesAnnotations.annotations_filter_trigger_button} 
  disabled={!annotationListFiltered.length} 
  title={__("dialog.deleteAnnotations")} 
  aria-label={__("dialog.deleteAnnotations")} // 静态标签,无动态状态提示
/>

当按钮因无选中注释而禁用时,屏幕阅读器无法自动播报"当前无可删除项",用户需手动探索状态。

2. 模态对话框的焦点陷阱

确认对话框(AlertDialog.Content)未实现无障碍焦点管理:

<AlertDialog.Content className={stylesAlertModals.AlertDialogContent}>
  <AlertDialog.Title>删除注释</AlertDialog.Title>
  <AlertDialog.Description>确定要删除选中的注释吗?</AlertDialog.Description>
  <div className={stylesAlertModals.AlertDialogButtonContainer}>
    <AlertDialog.Cancel>取消</AlertDialog.Cancel>
    <AlertDialog.Action>确认删除</AlertDialog.Action>
  </div>
</AlertDialog.Content>

对话框打开后焦点未自动移至"取消"按钮,键盘用户需多次Tab键才能到达操作区;删除完成后焦点未返回触发按钮,导致操作链路断裂。

3. 操作结果的不可感知性

删除操作通过dispatch(readerActions.note.remove.build(annotation))完成后,缺乏明确的屏幕阅读器反馈:

dispatch(readerActions.note.remove.build(annotation));
// 缺少操作结果的无障碍通知

用户无法通过听觉确认删除成功,需手动刷新注释列表才能验证操作效果。

技术优化方案:构建无障碍闭环

1. 动态状态感知系统

为删除按钮添加实时状态提示,通过aria-live区域播报状态变化:

// 在组件顶部添加状态播报区域
<div aria-live="polite" className="sr-only" id="delete-status-announcer" />

// 修改触发按钮
<AlertDialog.Trigger 
  className={stylesAnnotations.annotations_filter_trigger_button} 
  disabled={!annotationListFiltered.length} 
  title={__("dialog.deleteAnnotations")}
  aria-label={__("dialog.deleteAnnotations")}
  aria-describedby={!annotationListFiltered.length ? "delete-disabled-reason" : undefined}
/>
{!annotationListFiltered.length && (
  <span id="delete-disabled-reason" className="sr-only">
    {__("dialog.noAnnotationsToDelete")}
  </span>
)}

当按钮状态变化时,通过aria-live区域自动播报状态,无需用户主动查询。

2. 符合WCAG 2.1的焦点管理

重构对话框焦点逻辑,实现"打开-操作-关闭"全链路焦点控制:

const cancelButtonRef = useRef<HTMLButtonElement>(null);

useEffect(() => {
  if (dialogOpen) {
    // 对话框打开后聚焦取消按钮
    cancelButtonRef.current?.focus();
    // 监听Escape键关闭
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape') setDialogOpen(false);
    };
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }
}, [dialogOpen]);

// 删除完成后返回焦点
const handleDelete = () => {
  dispatch(readerActions.note.remove.build(annotation));
  setDialogOpen(false);
  triggerButtonRef.current?.focus(); // 返回触发按钮
};

// 对话框内容
<AlertDialog.Content className={stylesAlertModals.AlertDialogContent}>
  <AlertDialog.Title>删除注释</AlertDialog.Title>
  <AlertDialog.Description>确定要删除选中的{annotationListFiltered.length}条注释吗?</AlertDialog.Description>
  <div className={stylesAlertModals.AlertDialogButtonContainer}>
    <AlertDialog.Cancel ref={cancelButtonRef}>取消</AlertDialog.Cancel>
    <AlertDialog.Action onClick={handleDelete}>确认删除</AlertDialog.Action>
  </div>
</AlertDialog.Content>

3. 操作结果的多模态反馈

结合Toast组件实现听觉+视觉双重反馈:

import { toastActions } from "readium-desktop/common/redux/actions";
import { ToastType } from "readium-desktop/common/models/toast";

// 删除操作后触发无障碍通知
dispatch(readerActions.note.remove.build(annotation));
dispatch(toastActions.openRequest.build(
  ToastType.Success, 
  __("reader.annotations.deleteSuccess", {count: annotationListFiltered.length})
));

// 在Toast组件中强化无障碍属性 (src/renderer/common/components/toast/Toast.tsx)
<div 
  className={stylesToasts.toast}
  role="alert" // 声明为警告区域
  aria-live="assertive" // 紧急内容优先播报
  aria-atomic="true" // 整体内容更新时重新播报
>
  {message}
</div>

role="alert"aria-live="assertive"的组合确保屏幕阅读器立即播报删除结果,aria-atomic="true"保证完整句子被正确朗读。

量化优化效果:从合规到体验升级

WCAG 2.1标准符合性对比

评估项当前实现优化方案合规标准
操作提示静态标签动态状态播报3.3.1 错误识别(A级)
焦点管理无焦点控制自动焦点定位2.4.3 焦点顺序(A级)
状态通知无反馈机制ARIA实时区域4.1.3 状态消息(AA级)
键盘导航可聚焦但无序逻辑焦点链路2.1.1 键盘(A级)

开发实施清单

  1. 组件改造(优先级:高)

    •  为删除按钮添加动态aria-describedby
    •  实现对话框焦点自动管理
    •  强化Toast组件的无障碍属性
  2. 测试验证(优先级:中)

    •  使用NVDA+Firefox测试完整操作链路
    •  验证键盘仅操作的可行性
    •  检查屏幕阅读器播报文本的自然度
  3. 扩展适配(优先级:低)

    •  将优化方案抽象为AccessibleAlertDialog通用组件
    •  应用于书签删除、批量操作等类似场景

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值