# 无障碍

> Fabric.js 编辑器无障碍指南：撤销按钮名称清楚，屏幕阅读器能读到保存状态，支持键盘和对话框焦点。

Source: https://fabricjs-document-engine.jscrate.dev/zh/docs/guides/accessibility
Last updated: 2026-09-28

Fabric.js 画布是一张位图，屏幕阅读器看不到里面的对象。要做好 Fabric.js 编辑器无障碍，关键在画布周围的控件。引擎提供状态，按钮、对话框和状态文字由你的应用渲染。

## 撤销和重做按钮

```tsx
<button
  onClick={() => engine.undo()}
  disabled={!state.canUndo}
  aria-keyshortcuts="Control+Z Meta+Z"
>
  Undo
  {state.undoLabel ? (
    <span className="sr-only">: {state.undoLabel}</span>
  ) : null}
</button>
```

- 用真正的 `<button>` 元素，它们天然支持焦点和键盘操作。
- 把步骤标签，比如「Undo: Move rect」，放进可访问名称里。屏幕阅读器对 `title` 的支持并不可靠。
- `bindKeyboardShortcuts` 不会干扰输入框和 Fabric.js 文本编辑，键盘用户在那里仍能使用原生的文本撤销。

## 保存状态

礼貌地播报保存状态的变化，不要抢走焦点：

```tsx
<p aria-live="polite" aria-atomic="true">
  {state.saveStatus === "saving" && "Saving…"}
  {state.saveStatus === "saved" && "All changes saved"}
  {state.saveStatus === "unsaved" && "Unsaved changes"}
  {state.saveStatus === "error" && "Could not save. Retrying."}
  {state.saveStatus === "conflict" && "Someone else changed this document."}
</p>
```

让 `aria-live` 区域一直留在页面上，只改变它的文字。在变化那一刻才插入的区域，常常不会被播报。

## 用对话框让用户选择

冲突、恢复提示和缺失的图片都需要用户做决定。把它们放在 `<dialog>` 里，打开时把焦点移进去，关闭时把焦点还回去。每个选项都要写清楚，比如「保留我的版本」，而不是「确定」。

## 画布本身

- 给画布一个可访问名称：`<canvas aria-label="Floor plan editor">`。
- 用 `engine.toDocument().objects` 生成一份重要对象的文字列表。
- 提供用键盘移动选中对象的方法，比如方向键调用 `engine.transaction("Move", ...)`。

Fabric.js 编辑器无障碍还意味着不设时间限制。自动保存和恢复都在后台运行，从不要求用户快速响应。
