实现按钮悬停立体感的关键是叠加两层 box-shadow 并配合 translateY(-1px):第一层为 0 1px 1px rgba(0,0,0,0.2),模拟底边压暗;第二层为 0 2px 4px rgba(0,0,0,0.15),模拟离散投影,再加 0.15s ease 过渡强化按压反馈。

button:hover 用 box-shadow 实现立体感的关键参数
纯 CSS 的立体阴影不是加一层深色 shadow 就完事,关键在 box-shadow 的 z-direction 感觉——也就是通过偏移量 + 模糊半径 + 颜色明度组合出“凸起”错觉。默认的 box-shadow: 0 2px 4px rgba(0,0,0,0.2) 看起来平,是因为阴影太软、没层次。
真正有立体感的做法是叠加两层 shadow:
– 第一层:小偏移(0 1px)、极小模糊(1px)、稍深色(模拟紧贴按钮底边的压暗)
– 第二层:稍大偏移(0 2px)、中等模糊(4px)、更透明(模拟离散投影)
示例代码:
button:hover {
box-shadow:
0 1px 1px rgba(0,0,0,0.2),
0 2px 4px rgba(0,0,0,0.15);
}
- 别用
inset——它做的是内凹,和“按下去再弹起”的立体反馈相反 - 避免
y偏移超过3px,否则像浮空而非凸起 - 颜色推荐用
rgba(0,0,0,0.15)~0.25,太黑会显得脏,太透则无重量感
配合 transform: translateY(-1px) 强化按下反馈
只靠阴影不够“可交互”,用户需要视觉确认“这个按钮真的被我按了”。单纯改背景色或边框容易突兀,而轻微上移 + 阴影收紧,能模拟物理按键回弹前的压缩态。
立即学习“前端免费学习笔记(深入)”;
注意必须和 transition 配合,否则跳变:
button {
transition: all 0.15s ease;
}
button:hover {
transform: translateY(-1px);
box-shadow:
0 1px 1px rgba(0,0,0,0.2),
0 2px 2px rgba(0,0,0,0.1);
}
-
transform要写在 hover 规则里,且必须和box-shadow同时触发,否则出现“先上移后出影”或“先出影后上移”的割裂感 - 时间控制在
0.12s–0.18s,比默认0.2s更干脆;缓动用ease或cubic-bezier(0.4,0.2,0.2,1),避免 linear 的机械感 - 如果按钮本身有
border-radius,确保 hover 时不改变圆角值,否则边缘会抽搐
IE 和旧版 Safari 下 box-shadow 兼容性处理
IE10+ 和 Safari 6.1+ 原生支持 box-shadow,但 IE9 及更早版本完全不识别,Safari 5.1 仅支持单层 shadow。如果你的项目仍需兼容这些环境,不能靠 JS 补丁,得用降级策略。
- 对 IE9-:用
filter: progid:DXImageTransform.Microsoft.Shadow(...)(已废弃,仅作兜底,不推荐投入精力) - 更实际的做法是忽略旧浏览器的阴影,但保留
transform: translateY(-1px)—— 它在 IE9+ 用-ms-transform支持,且视觉反馈依然有效 - Safari 5.1 下两层
box-shadow会合并为一层,此时第二层失效,所以把最重要的那层(0 1px 1px)放在前面,确保基础立体感不丢
移动端点击无 hover 效果?别依赖 :hover
在 iOS Safari 和 Android Chrome 中,:hover 在触摸设备上行为不稳定:首次点击可能触发,之后就失效,或只在长按时生效。这不是 bug,是浏览器为兼容桌面悬停逻辑做的妥协。
真要保障触控反馈,得换思路:
- 用
:active替代:hover,它在触摸开始瞬间触发,且各平台一致性高 - 给 button 加
touchstart事件监听器,动态加 class(如is-pressed),然后用该 class 控制样式,比纯 CSS 更可控 - 注意
:active默认持续时间极短(约 100ms),需配合transition缓动才能看清效果,否则一闪即逝
立体阴影这事,细节全在像素和毫秒之间——偏移差 1px,明度差 5%,过渡快 20ms,体验就从“有点意思”变成“真想点一下”。



















