如何制作HTML商品评分星级显示效果?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1175个文字,预计阅读时间需要5分钟。
商品评分显示不需要JavaScript就能做,但必须使用标签。
为什么不能直接写 ★★★★☆
纯字符堆砌看起来像评分,实则只是静态文本:点击无效、无法提交、document.querySelector('input[name="score"]:checked') 查不到值、移动端双击放大、高对比度模式下可能消失。更严重的是,它完全绕过了表单语义——浏览器和辅助技术根本不知道这是个“可选的评分控件”。
常见错误包括:
- 把
<label>写在<input>前面(input:checked + label失效) - 用
display: none隐藏<input>(脱离可访问性树,tab键跳过、屏幕阅读器忽略) - 所有
<input>的name不一致(导致只能选一颗星,无法互斥)
怎么让 5 颗星从右往左排列并正确响应 :checked
关键在 direction: rtl 和 DOM 顺序配合。把 value="5" 的 <input> 放最左,value="1" 放最右,再用 direction: rtl 让视觉顺序反转——这样 input[value="3"]:checked ~ label 才能命中前 3 颗星(即视觉上最右边的三颗)。
立即学习“前端免费学习笔记(深入)”;
结构必须是:
<div class="rating"> <input type="radio" id="star5" name="score" value="5"><label for="star5">★</label> <input type="radio" id="star4" name="score" value="4"><label for="star4">★</label> <input type="radio" id="star3" name="score" value="3"><label for="star3">★</label> <input type="radio" id="star2" name="score" value="2"><label for="star2">★</label> <input type="radio" id="star1" name="score" value="1"><label for="star1">★</label> </div>
CSS 必须包含:
.rating { direction: rtl; display: inline-block; }-
.rating input { position: absolute; clip: rect(0 0 0 0); }(别用display: none) .rating input:checked ~ label { color: #ffc107; }.rating label { cursor: pointer; }
怎么显示 4.3 分这种带小数的评分(只读,不交互)
这是展示场景,不是用户输入,所以不用 radio。用两层重叠的星星图:底层灰色,上层金色,通过 width 控制上层显示比例。
例如 4.3 分(满分 5)对应 86% 宽度:
<div class="score-display"> <div class="stars-bg">★★★★★</div> <div class="stars-fg" style="width: 86%">★★★★★</div> </div>
CSS 要设为 position: relative + position: absolute 叠加,且两层字体、大小、行高严格一致。否则会出现错位或锯齿。
注意点:
- 别用图片——缩放、深色模式、DPR 变化时易糊或消失
- 别用 SVG 单独渲染——DOM 节点多,表格里批量渲染性能差
- 用 Unicode 星号 +
font-variant-numeric: slashed-zero;等字体控制更稳妥
表格里每行商品都要独立评分,怎么避免 name 冲突
每个商品行的 <input> 的 name 必须唯一,比如用商品 ID 拼接:name="score_1001"、name="score_1002"。但注意:如果整张表在一个 <form> 里,提交时后端会收到一堆键值对,需按约定解析。
更实际的做法是:
- 只在编辑态启用交互评分(
name动态生成),展示态用只读方式(上一节的遮罩法) - 用 JS 绑定事件时,用
event.target.closest('tr')定位当前行,再取该行内的input:checked,避免全局 name 管理 - 如果用框架(如 Vue/React),直接用数据驱动,
name属性反而可以省略
最容易被忽略的是:移动端点击区域太小,<label> 必须有足够 padding(至少 44×44px),否则手指点不中;另外,别给 <label> 加 pointer-events: none——那是给伪元素用的,不是给容器。
本文共计1175个文字,预计阅读时间需要5分钟。
商品评分显示不需要JavaScript就能做,但必须使用标签。
为什么不能直接写 ★★★★☆
纯字符堆砌看起来像评分,实则只是静态文本:点击无效、无法提交、document.querySelector('input[name="score"]:checked') 查不到值、移动端双击放大、高对比度模式下可能消失。更严重的是,它完全绕过了表单语义——浏览器和辅助技术根本不知道这是个“可选的评分控件”。
常见错误包括:
- 把
<label>写在<input>前面(input:checked + label失效) - 用
display: none隐藏<input>(脱离可访问性树,tab键跳过、屏幕阅读器忽略) - 所有
<input>的name不一致(导致只能选一颗星,无法互斥)
怎么让 5 颗星从右往左排列并正确响应 :checked
关键在 direction: rtl 和 DOM 顺序配合。把 value="5" 的 <input> 放最左,value="1" 放最右,再用 direction: rtl 让视觉顺序反转——这样 input[value="3"]:checked ~ label 才能命中前 3 颗星(即视觉上最右边的三颗)。
立即学习“前端免费学习笔记(深入)”;
结构必须是:
<div class="rating"> <input type="radio" id="star5" name="score" value="5"><label for="star5">★</label> <input type="radio" id="star4" name="score" value="4"><label for="star4">★</label> <input type="radio" id="star3" name="score" value="3"><label for="star3">★</label> <input type="radio" id="star2" name="score" value="2"><label for="star2">★</label> <input type="radio" id="star1" name="score" value="1"><label for="star1">★</label> </div>
CSS 必须包含:
.rating { direction: rtl; display: inline-block; }-
.rating input { position: absolute; clip: rect(0 0 0 0); }(别用display: none) .rating input:checked ~ label { color: #ffc107; }.rating label { cursor: pointer; }
怎么显示 4.3 分这种带小数的评分(只读,不交互)
这是展示场景,不是用户输入,所以不用 radio。用两层重叠的星星图:底层灰色,上层金色,通过 width 控制上层显示比例。
例如 4.3 分(满分 5)对应 86% 宽度:
<div class="score-display"> <div class="stars-bg">★★★★★</div> <div class="stars-fg" style="width: 86%">★★★★★</div> </div>
CSS 要设为 position: relative + position: absolute 叠加,且两层字体、大小、行高严格一致。否则会出现错位或锯齿。
注意点:
- 别用图片——缩放、深色模式、DPR 变化时易糊或消失
- 别用 SVG 单独渲染——DOM 节点多,表格里批量渲染性能差
- 用 Unicode 星号 +
font-variant-numeric: slashed-zero;等字体控制更稳妥
表格里每行商品都要独立评分,怎么避免 name 冲突
每个商品行的 <input> 的 name 必须唯一,比如用商品 ID 拼接:name="score_1001"、name="score_1002"。但注意:如果整张表在一个 <form> 里,提交时后端会收到一堆键值对,需按约定解析。
更实际的做法是:
- 只在编辑态启用交互评分(
name动态生成),展示态用只读方式(上一节的遮罩法) - 用 JS 绑定事件时,用
event.target.closest('tr')定位当前行,再取该行内的input:checked,避免全局 name 管理 - 如果用框架(如 Vue/React),直接用数据驱动,
name属性反而可以省略
最容易被忽略的是:移动端点击区域太小,<label> 必须有足够 padding(至少 44×44px),否则手指点不中;另外,别给 <label> 加 pointer-events: none——那是给伪元素用的,不是给容器。

