button:active 在 ios safari 不触发,因需原生可交互语义;用 最稳妥,或为 加 role="button" 和 tabindex="0",并设 touch-action: manipulation、-webkit-tap-highlight-color: transparent,且 transition 必须定义在常态样式中。

移动端 button:active 没反应,不是 CSS 写错了,而是浏览器压根没把它当可点击元素处理。
button:active 为什么在 iOS Safari 上不触发
iOS Safari 对 :active 的激活有硬性语义要求:只对原生可交互元素(如 <button></button>、<a></a>)或显式声明交互意图的元素生效。纯 <div class="btn"> 即使加了 <code>onclick,也大概率跳过 :active 计算流程。
- 最稳妥方案:直接用
<button type="button"></button>,零配置即生效 - 若必须用
<div>:必须同时加 <code>role="button"和tabindex="0" - 轻量兼容方案:加空属性
ontouchstart="",现代 iOS 支持良好,但动态插入的按钮需手动补上 - 检查 DevTools 的 Computed 面板,确认元素的
touchAction值为manipulation,而非被父容器的touch-action: none覆盖 - 必须写在可点击语义化元素上,例如:
button { touch-action: manipulation; }或[role="button"] { touch-action: manipulation; } - 写在
body或* { touch-action: manipulation }上不仅无效,还可能阻断轮播图、列表滑动等正常手势 - Android 4.4+ 和 iOS 9.2+ 全面支持;旧版 WebView 返回空字符串,说明未识别,需降级 fallback
- 搭配
-webkit-tap-highlight-color: transparent,否则 iOS 系统灰层会覆盖你的:active样式 - 错误写法:
button:active { transform: scale(0.96); transition: transform 0.08s; }——transition在:active里完全无效 - 正确写法:
button { transform: scale(1); transition: transform 0.08s ease, box-shadow 0.08s ease; } button:active { transform: scale(0.96); box-shadow: inset 0 1px 2px rgba(0,0,0,0.15); } - 避免
transition: all:颜色变化触发 repaint,低端安卓机卡顿明显;优先用transform和opacity(GPU 加速) - 时间控制在 0.06s–0.1s:PC 可用 0.06s,移动端建议 ≥0.08s;太短像没响应,太长反馈迟钝
- 必加
transform: scale(0.96)或transform: translateY(1px);缩放比位移更稳定,iOS 上translateY有时触发重排闪烁 - 配合
box-shadow: inset 0 1px 2px rgba(0,0,0,0.15)模拟受压内阴影,别漏inset关键字 - 常态按钮建议带轻微外阴影营造“凸起”感:
box-shadow: 0 2px 6px rgba(0,0,0,0.15),形成对比 - 深色模式下需单独覆盖:
@media (prefers-color-scheme: dark) { .btn:active { box-shadow: inset 0 2px 4px rgba(0,0,0,0.4); } }
touch-action: manipulation 加在哪才起作用
touch-action: manipulation 不是全局开关,它只对具体响应点击的目标元素生效。
transition 必须写在常态选择器里,不能只靠 :active
:active 是瞬态伪类,不是动画钩子。过渡效果必须定义在默认状态中,且所有要过渡的属性都得有明确初始值。
视觉反馈不能只靠 background-color 变化
在强光屏、小尺寸设备或深色背景上,单靠颜色变深/变浅几乎无法感知“按下”。真正有效的反馈依赖形变和光影变化。
真机测试前最容易忽略的是触控区域尺寸——iOS 要求最小点击区为 min-height: 48px,文字撑不开时 :active 直接被忽略;另外,父容器设了 pointer-events: none 或 overflow: hidden,也会把缩放后的阴影或边缘裁掉。











