按钮:active凹陷效果必须用transform和双inset box-shadow实现,禁用width/height/border变更;transition需写在常态规则中;移动端须加touch-action: manipulation和-webkit-tap-highlight-color: transparent。

button:active 位移必须用 transform,别碰 width/height/border
直接改 width、height 或 border-width 会导致 layout thrashing,外盒尺寸必然波动,且低端安卓机明显掉帧。真正零尺寸变更的凹陷,只靠 transform: translateY(1px) 或 transform: scale(0.98)——它们不触发重排,纯 GPU 合成。
实操建议:
-
transform: translateY(1px)更符合物理按压感,但 iOS 上偶发重排闪烁;若遇此问题,立刻换scale() - 绝对不要写
margin-top: 1px或padding-bottom: -1px,这些会破坏盒模型边界 - 如果按钮有
border,确保:active下不修改其宽度或颜色,否则 border 区域视觉上会“缩进”或“外扩”
box-shadow: inset 必须配对使用,且 y-offset 要为负
单条 box-shadow: inset 0 2px 4px rgba(0,0,0,0.2) 看起来是下压,其实是顶部变暗、底部没变化,缺乏真实挤压感。真正“内凹”需要模拟光源从上方来——顶部边缘压暗、底部边缘提亮。
正确写法是双内阴影组合:
立即学习“前端免费学习笔记(深入)”;
button:active {
box-shadow: inset 0 -2px 4px rgba(0,0,0,0.12), inset 0 2px 4px rgba(255,255,255,0.3);
}
注意点:
-
inset 0 -2px是关键:负 y 值让阴影压在顶部边缘,强化“被按下去”的错觉 - 第二条高光内阴影用浅白,透明度控制在
0.2–0.4,太浓像反光,太淡无效 - 两条阴影都带
inset,漏写一个就变成外凸+内凹混合,视觉打架
transition 必须写在常态规则里,且只限定属性
:active 是瞬时伪类,本身不支持 transition。所谓“动画”,其实是常态下的过渡声明在状态切换时生效。写错位置或范围,就会卡顿、延迟、或干脆不动。
正确结构示例:
button {
transform: scale(1);
box-shadow: 0 2px 6px rgba(0,0,0,0.15), inset 0 -1px 2px rgba(0,0,0,0.05);
transition: transform 0.08s ease, box-shadow 0.08s ease;
}
button:active {
transform: scale(0.98);
box-shadow: inset 0 -2px 4px rgba(0,0,0,0.12), inset 0 2px 4px rgba(255,255,255,0.3);
}
常见错误:
- 在
button:active里写transition——完全无效 - 用
transition: all——background-color变化触发 repaint,移动端肉眼可见卡 - 时间设成
0.03s——多数设备响应不过来,像没动;设成0.2s——反馈迟钝,用户会连点两次
移动端必须加 touch-action: manipulation 和 -webkit-tap-highlight-color
iOS Safari 和部分安卓浏览器默认禁用 :active 的即时激活,尤其对非 <button></button> 元素。即使样式写对,点击时也毫无反应——不是你的 CSS 错,是浏览器根本没触发 :active 状态。
绕过方式只有两个硬性条件:
- 元素必须是
<button></button>,或至少带role="button" tabindex="0" - CSS 中必须显式声明:
touch-action: manipulation(解除 300ms 延迟) +-webkit-tap-highlight-color: transparent(干掉灰色闪屏) - 顺手加
user-select: none,防止长按误触发文字选中覆盖凹陷效果
这三行不是可选项,缺一不可。漏掉 touch-action,:active 在真机上就是摆设。
最易被忽略的是:凹陷效果依赖背景色与阴影的动态匹配。写死 rgba(0,0,0,0.2) 在深色模式下会糊成一片,必须用 CSS 变量锚定到当前主题色,否则换肤后按钮就“塌”了。


















