原生html需用aria+js模拟语义化switch/slider:switch须设role="switch"、aria-checked、tabindex="0"及aria-label;range需补全aria-valuetext等属性并js同步状态,兼顾焦点、键盘与视觉一致性。

原生 HTML 没有语义化的 switch 或带范围反馈的 slider 控件,必须靠 ARIA + JS 手动模拟,否则屏幕阅读器无法正确识别状态和操作方式。
怎么让 div 或 span 被读作 switch
不能只加 role="switch" —— 这只是告诉屏幕阅读器“这是个开关”,但没定义可交互性或当前状态。必须同时设置:
-
role="switch"(固定角色) -
aria-checked="true"或aria-checked="false"(动态反映开/关) -
tabindex="0"(确保键盘可聚焦) -
aria-label或aria-labelledby(提供可读名称,不能依赖纯视觉文字)
常见错误:漏掉 aria-checked,导致 NVDA/JAWS 读成“开关,未选中”但实际已开启;或用 aria-hidden="true" 包住图标,反而把状态描述也隐藏了。
为什么 input[type="range"] 不能直接当 slider 用
它本身有 role="slider",但默认缺乏关键 ARIA 属性支持:
- 不自动暴露
aria-valuetext,屏幕阅读器只会读数值(如“50”),而不会读“音量:中等”这类上下文化描述 - 移动端 Safari 对
input[type="range"]的aria-live支持不稳定,拖动时状态更新常被跳过 - 无法自定义步进逻辑(比如按百分比变化但需映射到离散档位),必须监听
input事件并手动同步aria-valuenow和aria-valuetext
示例补全点:<input type="range" aria-valuetext="亮度:高" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"> —— 缺少 aria-valuetext 就只剩干巴巴的数字。
JS 同步状态时最容易错的三件事
所有 ARIA 属性都得在 DOM 更新后立刻同步,延迟哪怕一帧,AT(辅助技术)就读到旧值:
- 用
click或keydown(空格/回车)切换switch时,先改aria-checked,再触发业务逻辑,别反过来 - 拖动
range时,在input事件里更新aria-valuenow和aria-valuetext,别只在change事件里做(后者只在松手后触发) - 避免用
innerHTML重写整个控件 DOM —— 会清空焦点、重置 AT 缓存,改用setAttribute()单独更新属性
兼容性注意:旧版 JAWS 对 aria-valuetext 的读取依赖是否设置了 aria-live="polite",但加了又可能重复播报,稳妥做法是只在用户主动操作后调用 aria-live 区域做一次提示。
真正难的不是加几个属性,而是每次交互都要同时满足:DOM 状态、ARIA 属性、焦点管理、键盘行为(Tab/Shift+Tab/Space/Enter/Arrow)、以及视觉反馈一致性 —— 少一个,就有人用不了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











