纯css星评组件若不处理可访问性,必 fail wcag 2.1 aa:屏幕阅读器读不出评分、键盘不可操作、焦点不可见、状态不明确;需用视觉隐藏而非display:none,配role="radiogroup"、aria-checked、aria-live等确保语义与交互同步。

纯 CSS 实现的 StarRating 组件若不加处理,几乎必然失败于可访问性测试——屏幕阅读器读不出评分值、键盘无法操作、焦点不可见、状态不明确,这些不是“体验问题”,而是 WCAG 2.1 AA 级合规的硬性门槛。
为什么display: none或visibility: hidden会直接废掉可访问性
很多开发者用 display: none 隐藏原生 input type="radio",以为“视觉藏了就行”。但这样会让屏幕阅读器完全忽略该控件,键盘 Tab 也无法聚焦,aria-labelledby 失效,整个评分变成“不可感知、不可操作、不可理解”的黑盒。
必须保留语义化结构,仅通过视觉手段隐藏:
- 用
position: absolute; clip: rect(0 0 0 0); width: 1px; height: 1px; margin: -1px; overflow: hidden;移出视口但保留在 DOM 流中 - 确保每个
input有唯一id,对应label[for],且label包含可读文本(如“3星:满意”) - 禁用
opacity: 0单独使用——它仍可被聚焦,但无视觉反馈,违反焦点可见性要求
:focus-visible 和键盘导航的强制配合
鼠标用户悬停时高亮星星,键盘用户按 Tab 进入时也必须有同等清晰的焦点指示。CSS 中仅靠 :hover 不够,:focus 又会在鼠标点击后残留,正确做法是:
- 启用
:focus-visible(现代浏览器已广泛支持),只在键盘触发时显示焦点环 - 为每个
label添加tabindex="0"是错误的——它会破坏原生 radio 的单选逻辑和 Tab 顺序;应只让第一个input可 tab 进入,其余由方向键切换 - 用 JavaScript 监听
keydown(ArrowRight/ArrowLeft)手动控制选中,同时保持checked状态同步到 input
如何让屏幕阅读器准确播报“4.5 星(共 5 星)”
单纯靠 aria-label 写死“4.5星”不行——它不会随用户选择实时更新。必须结合动态属性:
- 给包裹整个评分组的容器加
role="radiogroup"和aria-label="商品满意度评分" - 每个
input加aria-label="选择 3 星",并用aria-checked="true/false"同步状态 - 用
aria-live="polite"的辅助区域(隐藏但可读)实时输出:“已选择 4.5 星,共 5 星”,避免打断主流程 - 避免用伪元素(
::before)生成星号文字——它们默认不被读取,需额外加aria-hidden="true"并补全语义文本
最易被忽略的一点:半星评分(如 4.5)在无障碍层面本质是“两个独立控件的组合状态”,纯 CSS 无法可靠表达其可读性。若业务强依赖半星,input[type="range"] + 自定义轨道+JS 计算,比强行 hack radio 更符合可访问性设计原则。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











