button:active 应用 transform: translatey(2px) 实现真实按压感,配合 box-shadow 垂直偏移同步收缩(如 2px→1px),小按钮用 1px、常规按钮用 2px,且必须声明 transition 在默认状态,禁用 margin-top/top,避免 inset 阴影与位移冲突。

button:active 必须用 transform: translateY(2px) 向下位移
向下位移才是“被按下去”的物理直觉,写成 translateY(-2px) 是往上飘,用户会感觉按钮被拎起而不是受压。真实按钮受力时底部压缩、整体微沉,对应视觉就是向下偏移。
常见错误现象:transform: translateY(1px) 在高 DPI 屏幕上几乎不可见;translateY(3px) 又太重,按钮像塌陷进页面里。实测 1–2px 最稳:小按钮(24–32px 高)用 1px,常规按钮(40–48px)用 2px。
- 位移值必须和常态
box-shadow的垂直偏移(第一个数值)对齐。比如常态是box-shadow: 0 2px 4px ...,那translateY(2px)才能严丝合缝,不露白边 - 别用
margin-top或top替代transform—— 前两者触发布局重排,卡顿明显;transform走合成层,GPU 加速,移动端也稳 - 过渡必须声明在默认状态,不是
:active里:transition: transform 0.1s ease, box-shadow 0.1s ease
box-shadow 在 :active 中必须同步收缩,不能只改颜色或透明度
只调 background-color 或只减 opacity,用户根本感知不到“按下”。真正反馈来自两个同步变化:阴影变短 + 位移下沉。否则就像按钮在原地变色,没重量感。
推荐组合(浅色背景):
常态:box-shadow: 0 2px 4px rgba(0,0,0,0.15)
:active:box-shadow: 0 1px 2px rgba(0,0,0,0.2)
- 外阴影的垂直偏移(第二个值)要减小,模糊半径(第三个值)也要收窄,但透明度可略增——模拟受压后边缘明暗对比增强
- 避免用
inset阴影:它制造的是“挖进去”的凹坑感,和translateY(2px)的下沉方向冲突,视觉割裂 - 深色模式下
rgba(0,0,0,0.15)可能失效,需加媒体查询:@media (prefers-color-scheme: dark) { button { box-shadow: 0 2px 4px rgba(0,0,0,0.25); } }
移动端 :active 不触发?三个硬性补救点
iOS Safari 和部分安卓 WebView 默认不响应非语义化元素的 :active,尤其用 <div> 冒充按钮时,点击毫无反馈。
<ul>
<li>优先用 <code><button></button> 元素 —— 它原生支持 :active,无障碍友好,不用额外 hack
<div>,加空属性 <code>ontouchstart="",绕过 300ms 延迟,激活伪类
cursor: pointer(让 Android 识别可点击态)+ touch-action: manipulation(提前告诉浏览器这是操作意图,非滚动)父容器 overflow: hidden 裁掉按下效果?
按钮 :active 时 translateY(2px) + 阴影收缩,但父级设了 overflow: hidden,阴影下半截直接被切掉,看起来像卡住了一半。
典型场景:卡片内按钮、Modal 底部操作区、Flex 容器中 align-items: center + overflow: hidden 组合。
- 检查按钮所有上级容器,逐个确认是否含
overflow: hidden;如有,改为overflow: visible或加足够padding-bottom - 真机测试比模拟器可靠:很多模拟器无法还原
:active的实际持续时间(约 100ms)和位移量,容易误判效果完整 - 别堆参数追求“立体”,重点是阴影方向、明度差、位移量三者匹配 —— 同一套值在深色模式、高 DPI、窄屏下都可能失准











