必须用 radio+label 结构并正确隐藏 input,滑块用 transform 实现平滑居中移动,严格保障可访问性与 ios 兼容性。

为什么直接用 justify-content: space-between 做分段控制器在 iOS 上会错位
它依赖容器剩余空间均分,但 iOS Safari(尤其 15.6 之前)对 flex 容器内 label 的宽度计算不稳定:文字撑开、图标加载延迟、font-smoothing 差异都会导致实际宽度不一致。更关键的是,space-between 无法绑定到选中状态,滑块位置只能靠 JS 或冗余 DOM 控制,失去纯 CSS 可访问性优势。
必须用 input[type="radio"] + label 结构,且不能 display: none
iOS Safari 会跳过 display: none 的 input,导致 VoiceOver 读不出当前选项,键盘 Tab 也无法聚焦。正确隐藏方式是:
-
position: absolute移出渲染流 -
opacity: 0和pointer-events: none防止误触 -
width: 1px; height: 1px;确保最小可访问尺寸 -
label必须设display: block; width: 100%; height: 100%,并加-webkit-tap-highlight-color: transparent -
for和id必须严格匹配,且input与label同级(不能嵌套)
滑块平滑移动必须用 transform: translateX(),不是 left
left 触发重排,iOS Safari 在 flex 容器中计算 offset 常偏移;transform 是合成属性,GPU 加速稳定。关键写法:
- 容器设
position: relative - 滑块元素设
position: absolute; top: 0; bottom: 0 - 每个
input[value="a"]声明变量:--offset: 0;input[value="b"]声明:--offset: 100% - 滑块样式:
transform: translateX(calc(var(--offset, 0) - 50%))(减去自身宽一半,居中对齐) - 过渡只写:
transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1),别用all
旧版 iOS(≤ 11.2)需补 -webkit- 前缀且禁用 gap
iOS 11.2 以下不支持 gap,也不识别 flex: 1 简写。必须显式写:
display: -webkit-flex; display: flex-webkit-flex-grow: 1; flex-grow: 1-webkit-justify-content: center; justify-content: center- 放弃
gap,改用margin或伪类:not(:last-child)控制间距 - 避免
flex-wrap: wrap—— iOS 8–10 中行为不可控,分段控制器本就不该换行
真正卡住的点不在动画本身,而在变量作用域和可访问性链路:CSS 变量必须绑定到 input 元素上,不能只写在父容器;而 opacity: 0 + pointer-events: none 的组合,是唯一既满足无障碍又不破坏点击热区的隐藏方案。漏掉任一环,iOS 上就只剩视觉效果,没有交互实质。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











