button:active 必须显式定义样式,仅靠浏览器默认行为无法呈现明显下凹效果;需配合 transform: translateY(1px/2px) 与 inset box-shadow,并统一各状态 border-width,同时注意移动端 touch-action、transition 位置及深色模式阴影适配。

button:active 必须显式写,不能靠默认行为
浏览器对 :active 的默认处理极弱——可能只是短暂变暗或焦点偏移,完全看不出“下凹”。不手动覆盖样式,就等于没效果。很多开发者写了 :active 却没反应,第一反应是“CSS 没生效”,其实是因为没给它定义视觉变化。
关键点::active 是瞬态伪类,只在鼠标按下/手指触碰的几十毫秒内存在,必须用足够快、足够明显的样式变化抓住这个窗口。
- 必须声明
transform: translateY(1px)或translateY(2px)(别超2px,否则假) - 必须配
box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),单靠位移或单靠阴影都不像真按下去 - 所有状态(
:hover、:focus、:active)的border-width要一致,否则transform会引发布局抖动
移动端 :active 不触发?先检查 touch-action 和 cursor
iOS Safari 默认禁用 :active,Android Chrome 有时延迟触发,这是最常被忽略的兼容性坑。空写一堆 :active 样式,在手机上根本不会动。
- 给按钮加
touch-action: manipulation,这是激活移动端:active的最小必要条件 - 同时确保有
cursor: pointer,部分 Android 浏览器依赖这个来识别可点击元素 - 避免在按钮父容器上设
overflow: hidden,它可能裁掉translateY后多出的阴影或边框 - 如果仍失效,用
addEventListener('touchstart', () => el.classList.add('pressed'))手动加 class,但优先走 CSS 方案
transition 写错位置,动画就卡顿或消失
:active 状态本身不负责过渡,过渡必须写在默认状态(即未激活时)的 transition 声明里。写成 button:active { transition: ... } 是无效的。
立即学习“前端免费学习笔记(深入)”;
- 正确写法:
button { transition: transform 0.12s cubic-bezier(0.2, 0, 0.1, 1), box-shadow 0.12s; } - 别用
transition: all—— 在某些浏览器中会漏掉box-shadow或transform的过渡 -
cubic-bezier(0.2, 0, 0.1, 1)比ease更自然:开头稍快,结尾带收束感,模拟真实按压回弹 - 时间控制在
0.1s–0.15s:短于0.1s用户几乎看不到,长于0.15s就像卡顿
深色模式下凹陷失效?阴影对比度要重调
同一套 inset 阴影在浅色背景上显得凹,在深色背景上可能发灰、发亮甚至反向凸起。这不是 bug,是光影逻辑被破坏了。
- 深色主题下,把
rgba(0,0,0,0.15)改成rgba(0,0,0,0.3),增强暗部强度 - 高光层(如
inset 0 -1px 2px rgba(255,255,255,0.6))在深底上要降透明度,比如改到0.2,否则边缘过曝 - 别只调阴影——同步调
background-color(变暗 5–10%)和border-color(加深),否则凹陷区域孤立失真 - 可用
@media (prefers-color-scheme: dark)包裹整套:active样式,避免混用
translateY(1px) 到 translateY(2px);超过这个值,再配合错误的阴影方向或透明度,用户第一反应不是“按下去了”,而是“这按钮卡了”。



















