用<input type="radio">实现五星评分的核心是:5个同name的radio隐藏于label下方,通过input:checked + label控制高亮,label用for绑定或包裹input,确保可访问性、键盘操作和表单提交。
直接用原生 HTML + CSS 就能实现一个可点击、可 hover、支持半星、无障碍友好的五星评分组件,不需要任何框架或 JS 也能完成基础交互;但要支持“只读显示”“动态更新”“键盘操作”和“表单提交”,JS 是绕不开的。
<input type="radio"> 实现可点击五星核心思路是把 5 个 <input type="radio"> 叠在星星图标下方,用 label 关联并覆盖视觉层。浏览器原生 radio 组天然保证单选,且自带 focus/checked 状态。
关键点:
<input> 的 name 必须相同(如 name="rating"),value 设为 1~5label 用 for 属性绑定 id,或直接包裹 input(更稳妥)input 定位到星星下方并设 opacity: 0; position: absolute;,避免遮挡但保留可点击区域input:checked ~ label 或 input:focus ~ label 控制高亮样式(注意兄弟选择器限制)示例结构片段:
立即学习“前端免费学习笔记(深入)”;
<div class="star-rating"> <input type="radio" id="star5" name="rating" value="5"> <label for="star5">★</label> <input type="radio" id="star4" name="rating" value="4"> <label for="star4">★</label> <!-- ... --></div>
:hover 和 :focus 星星状态容易错乱纯 CSS 实现 hover 效果时,常见错误是只给 label:hover 上色,结果鼠标从一颗星移到相邻星时,中间有空隙导致状态重置;focus 问题则多因 radio 本身不可见,键盘 tab 到它时没有视觉反馈。
解决方式:
label 用 display: inline-block 并设 margin: 0,消除默认间隙.star-rating:hover label + .star-rating:hover label:hover ~ label 实现“悬停某星,左侧全亮”input:focus + label 单独加 outline 或 box-shadow,确保键盘用户可见焦点value 做条件匹配radio 组提交时只会发选中的那个 value,但很多场景需要读取当前值(比如点击后触发 API)、或初始化时设默认值(如编辑已有评分)。
实操要点:
input 加 checked 属性,或用 JS 设置 document.querySelector('[value="3"]').checked = true
change 事件(不是 click),绑定到 name="rating" 的任意 radio 上即可document.querySelector('input[name="rating"]:checked)?.value —— 注意空值判断name,否则互相干扰简单监听示例:
document.querySelectorAll('input[name="rating"]').forEach(radio => { radio.addEventListener('change', () => { const val = document.querySelector('input[name="rating"]:checked')?.value || '0'; console.log('当前评分:', val); });});
无障碍(a11y)和移动端适配是高频翻车点,不是“锦上添花”,而是“不加就残缺”。
aria-label 或 aria-labelledby:屏幕阅读器无法知道这是“评分”,应加在容器上,如 aria-label="请为该商品打分,满分5星"
label 最小尺寸设为 min-height: 44px 并居中图标value="0" 的 radio 或用 JS 清除 checked★)比引用外部 iconfont 更可靠真实项目里,最常被砍掉的是键盘导航和屏幕阅读器支持,结果上线后被合规团队打回 —— 这些不是“高级功能”,是基础可用性门槛。