跳到主要内容

GPU无障碍

<canvas> 无论 2D 还是 GL,对读屏都是 一张位图。没有对象树,没有可聚焦的 mesh。可交互 GL(查看器、散点、地图)必须在 DOM 里另建投影:列表、滑块、live region。role="img" 只够静态图。

1. 静态 vs 可交互

<canvas role="img" aria-label="2026 Q3 销售额三维柱状图,华东最高"></canvas>

适用:海报、烘焙好的预览、不会被点的背景。
不适用:要选中标记、改相机、改筛选的产品——读屏只能听到一句标签,操作全丢。

可交互最低交付:

能力DOM 投影
对象列表listbox / 表格,与场景 id 双向同步
当前选中aria-activedescendant 或焦点移到对应行
相机 / 时间input type="range",改的是 CPU 相机,GL 只提交
动态结果aria-live="polite" 摘要,不要每帧报

场景图在 CPU,这件事反而简单:列表渲染的就是那份数组,不是 readPixels

2. 键盘

轨道球和缩放必须有键盘等价:方向键平移、+/- 缩放、0 重置。焦点在 canvas 上时 tabindex="0",并在 keydownpreventDefault 掉会滚页面的键。焦点在 overlay 输入里时不要抢键。

命中高亮和列表高亮必须同一 selectedId。只在 GL 里画轮廓、列表不更新,等于视觉用户和读屏用户看到两套程序。

3. 不要拿 fallback HTML 当树

canvas 元素里的子 HTML 是 无脚本时的后备内容,现代浏览器有 GL 时读屏不一定进这棵树。生产把可访问控件放在 canvas 外面,不要塞进标签里当「隐藏 a11y」。细节同类问题见 Canvas 无障碍

对比 SVG:节点可以挂 title / role。选 GL 就是放弃这棵树,必须用 overlay 买回来。

4. 失败形态

症状原因
读屏只有「画布」可交互图只用了 role=img
键盘转了相机,列表还停在旧选中两套状态
后备 HTML 有列表,读屏读不到后备不在无障碍树上
每秒朗读一百次live region 绑在了 rAF

权威资料

核对日期:2026-08-26