语义(Semantics)
本页介绍如何在新版 Web (JS) 运行时中启用语义,让你的 Rive 图形可被屏幕阅读器访问。要了解什么是语义以及如何将其添加到图形中,请参阅编辑器文档中的语义。
概述
在 Rive 编辑器中,你可以为图形的某些元素添加语义含义——例如 button、checkbox、tab、image、list、dialog 等角色,以及相关的标签、值、状态和动作。这些设置因角色而异。
在运行时,Web (JS) 运行时会从正在运行的状态机中读取这些语义,并在你的 <canvas> 旁边构建一个不可见的 DOM 树,随着状态机推进保持同步。
由于 <canvas> 对辅助技术(AT)是不透明的,这个 DOM 叠加层正是使你的图形可被发现的关键。每个语义节点都成为一个真实的 DOM 元素,具有匹配的 ARIA 角色、属性和键盘处理程序,并定位在 Rive 图形中对应节点的上方。
语义是选择启用的。默认模式为 SemanticMode.Disabled,因此在启用语义之前不会创建任何语义 DOM。作为实验性 API,semanticsMode 和 semanticsOptions 可能会在不进行主版本升级的情况下更改行为。
必须在编辑器中定义语义才会产生效果。如果元素没有语义,则不会暴露给屏幕阅读器——无论你设置什么模式。请参阅功能支持,了解当前哪些运行时支持语义。
语义模式
语义由 SemanticMode 枚举控制,你从 Rive 包中导入该枚举,并在实例化 Rive 时作为参数传递:
| 模式 | 说明 |
|---|---|
SemanticMode.Disabled | 默认。 禁用语义。不会创建语义树或无障碍 DOM。 |
SemanticMode.Enabled | 语义已激活。无障碍 DOM 在加载后创建,并随着状态机推进保持更新。 |
用法
导入 SemanticMode,并在实例化 Rive 时将其作为 semanticsMode 传递。
import { Rive, SemanticMode } from "@rive-app/webgl2";
const rive = new Rive({
canvas: document.getElementById("rive-canvas"),
src: "login.riv",
stateMachine: "State Machine 1",
autoplay: true,
autoBind: true,
semanticsMode: SemanticMode.Enabled,
});
加载后启用语义
如果你想以编程方式控制何时启用语义,可以在构造 Rive 时使用默认的 SemanticMode.Disabled,并在用户选择启用时调用 enableSemantics() 方法。
const rive = new Rive({
canvas: document.getElementById("rive-canvas"),
src: "login.riv",
stateMachine: "State Machine 1",
semanticsMode: SemanticMode.Disabled,
autoplay: true,
autoBind: true,
});
accessibilityToggle.addEventListener("change", (event) => {
if (event.target.checked) {
rive.enableSemantics();
}
});
标注图形
语义叠加层的容器元素是一个 role="region" 地标。在实例化 Rive 时使用 semanticsOptions.riveCanvasLabel 参数为其设置一个 aria-label,描述图形是什么,以便屏幕阅读器用户知道他们正在进入什么。
const rive = new Rive({
canvas: document.getElementById("rive-canvas"),
src: "login.riv",
stateMachine: "State Machine 1",
autoplay: true,
autoBind: true,
semanticsMode: SemanticMode.Enabled,
semanticsOptions: {
riveCanvasLabel: "Login Experience",
},
});
| 选项 | 类型 | 说明 |
|---|---|---|
riveCanvasLabel | string | 应用于叠加层容器的 aria-label。默认 为 "Rive animation"。 |
语义如何映射到 DOM
运行时将每个编辑器语义角色转换为 ARIA 角色,将每个状态和特征转换为匹配的 ARIA 属性。在大多数情况下,这些属性附加到 <div> 元素上,以在各浏览器中统一样式/布局模式。文本内容包裹在内部 <span> 中,以辅助 AT 浏览文本。
在语义功能处于抢先体验阶段时,这组角色和特征可能会发生变化。
| 编辑器角色 | DOM 输出 |
|---|---|
| Button | role="button" |
| Checkbox | role="checkbox" |
| Switch | role="switch" |
| Slider | role="slider" |
| Text | 文本作为 DOM 文本内容存在于内部 <span> 中,父级为 <div>。对于标题,<div> 具有 role="heading" 并设置 aria-level。 |
| Image | role="img",但必须有标签 |
| Group / None | role="group" |
| List / List item | role="list" / role="listitem" |
| Tab / Tab list | role="tab" / role="tablist" |
| Dialog / Alert dialog | role="dialog" 带 aria-modal(模态时)/ role="alertdialog" 始终带 aria-modal |
| Radio group / Radio button | role="radiogroup" / role="radio" |
状态和特征映射到 ARIA 属性,如 aria-expanded、aria-selected、aria-checked、aria-pressed、aria-required 和 aria-disabled。只有当编辑器中存在相应特征或 ARIA 要求其存在时,才会设置属性,因此 AT 看到的是"不适用"而非"false"。
- 标签(Label) 变为
aria-label(对于文本节点则变为 DOM 文本内容)。 - 提示(Hint) 变为视觉隐藏的描述,通过
aria-describedby引用。 - 滑块的值(Value) 变为
aria-valuenow和aria-valuetext。 - 隐藏(Hidden) 变为
aria-hidden="true"。 - 实时区域(Live Region) 变为
aria-live="polite"。
没有标签的图像被视为装饰性图像,会对辅助技术隐藏,因为没有可访问名称的 role="img" 元素不符合 WCAG 标准。请在编辑器中为任何有意义的图像添加标签。
其他注意事项
Tab index
可交互、可聚焦和列表项叠加层元素被赋予 tabindex="-1",这使它们不在浏览器的顺序 Tab 导航中;其余元素不携带 tabindex。这些元素仍可被屏幕阅读器的光标访问,但仅使用键盘的视力用户无法 Tab 到图形内的单个元素。
语义叠加层定位
Rive 会在画布调整大小或移动时保持叠加层与画布匹配。运行时会监视画布、其父级和窗口的变化并重新同步叠加层,因此常见场景无需额外工作。
叠加层容器作为 <canvas> 的兄弟节点插入,并使用画布的布局偏移进行定位。如果可能,请为画布的容器设置 position: relative,以便叠加层和画布相对于相同的祖先解析位置。如果画布没有已定位的祖先,叠加层将相对于文档解析,<body> 的边距会使其偏离画布。
测试语义
在运行时启用语义后,打开屏幕阅读器并导航你的图形:
- macOS / iOS:VoiceOver
- Android:TalkBack
- Windows:Narrator 或 NVDA
检查每个元素是否播报了清晰的标签、正确的角色、准确的值和状态,以及导航是否遵循逻辑顺序。你也可以在浏览器的开发者工具中检查生成的 DOM——查找紧随画布之后的 <div id="rive-a11y-..."> 元素——或使用浏览器的无障碍树检查器。
完整检查清单请参阅编辑器文档中的测试语义。