纯css移动端星级评分必须用:checked + label绑定并加ontouchstart=""激活伪类,因ios safari仅首次点击后临时响应:hover,后续失效;dom须逆序排列(star5→star1)并配合flex-direction:row-reverse实现前序高亮,隐藏input须用clip而非display:none以保障可访问性。

纯 CSS 实现移动端评分星星,hover 不可靠,必须用 :checked + label 绑定 + ontouchstart="" 强制激活伪类,否则 iPhone 上点一次就失效。
为什么移动端不能只靠 :hover
iOS Safari 对 :hover 的支持极弱:默认仅在首次点击后临时触发,后续悬停完全不响应。这意味着仅靠 input:hover ~ label 的方案,在真机上会“点一下亮一颗,再点没反应”。这不是 bug,是 WebKit 的主动限制——它把 :hover 当作桌面遗留行为,默认禁用。
- 必须给每个
<input>加空属性ontouchstart=""(哪怕什么都不做),才能让 iOS 愿意识别并激活后续的:hover或:focus伪类 - 但仅靠
:hover仍不可靠:用户可能快速滑过、误触、或使用语音控制,所以核心交互必须基于:checked -
label的for属性必须严格匹配input的id,否则点击无效——这是移动端最常漏检的错误
flex-direction: row-reverse 是必须项,不是可选项
兄弟选择器 ~ 只能选中“当前元素之后”的同级元素,无法往前选。要实现“点第 3 颗星,前 3 颗都亮”,DOM 顺序必须是 star5 → star4 → star3 → star2 → star1,再用 flex-direction: row-reverse 把视觉顺序翻回来。任何试图用 transform: scaleX(-1) 或 direction: rtl 替代的做法都会失败——它们不改变 DOM 顺序,~ 依然选不到前面的 label。
- HTML 中
<input>必须紧挨着对应<label></label>,且<input>在前、<label></label>在后,层级不能被<div> 打断<li>容器必须设 <code>display: flex+flex-direction: row-reverse,并加gap控制间距,避免 Safari 在 flex-wrap 下换行错位 - 别用
width: 100%或max-width: 100%让容器自适应——iOS Safari 对 flex + row-reverse + 百分比宽度的计算有偏差,固定宽度(如width: 120px)更稳 -
clip: rect(0 0 0 0)兼容性更好(IE9+),clip-path在 iOS 15.4+ 才稳定,旧版本会失效 - 必须保留
tabindex="-1"或确保label有明确cursor: pointer,否则触屏设备可能判定为不可点击区域 - 每个
input的name属性必须唯一 per 组(如name="rating-1"),否则多组评分会互相干扰 - 推荐方案:外层容器
overflow: hidden+ 底层灰色星 + 上层金色星(用::before),通过width百分比控制露出比例,例如width: calc(var(--fill-ratio) * 20%) - CSS 变量
--fill-ratio由 JS 注入(如el.style.setProperty('--fill-ratio', '3.7')),配合transition: width 0.3s ease实现平滑填充 - 别用
background-position过渡——多数浏览器不触发重绘,会直接跳变;也别用clip-path: polygon(),Chrome/Firefox 插值不一致,容易锯齿
隐藏 <input> 的正确写法是 clip,不是 display: none
display: none 会让元素彻底脱离可访问性树和表单提交流程,屏幕阅读器读不到,键盘 Tab 也无法聚焦,且部分安卓浏览器会忽略其关联的 label。真正安全的隐藏方式是用 position: absolute + clip: rect(0 0 0 0)(或现代写法 clip-path: inset(100%))。
半星和小数评分只能靠双层结构或 CSS 变量,:checked 无解
:checked 只能表示离散整数值(1–5),无法表达 3.7 这类小数。若需半星效果,必须放弃单选按钮逻辑,改用纯展示模式:
真正的难点不在样式,而在状态同步:JS 更新变量时必须防抖、校验范围 [0,5]、并兼容 Safari 对 CSS 变量动画的延迟响应。这些细节一漏,移动端就会出现“点完不更新”或“滑动时卡顿”。











