真实立体感需同步box-shadow offset-y增大与transform: translatey(-2px)上移,且二者transition必须同写于默认状态并共用缓动函数,否则视觉脱节。

box-shadow 偏移值必须配合 transform: translateY 才真实
只改 box-shadow 的 offset-y(比如从 2px 到 8px)会让阴影“往下掉”,但人眼感知的“上浮”需要卡片本身轻微上移。纯靠阴影偏移,视觉上是卡片被“顶起来”,而不是“自己飘起来”。
正确做法是两者同步:
-
box-shadow的offset-y适当增大(如0 6px→0 12px),模拟离背景更远 -
transform: translateY(-2px)同步应用,让卡片物理位置微抬,强化上浮直觉 - 两个属性都写进同一段
transition,且用相同缓动函数,否则会脱节
transition 必须写在默认状态,不是 :hover 里
很多人把 transition: box-shadow 0.3s 写在 .card:hover 块里,结果鼠标移入有动画、移出却“啪”一下跳回——因为基础状态没声明过渡行为,浏览器默认立刻还原。
真正有效的写法是:
.card {
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
transition: box-shadow 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
transform 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.card:hover {
box-shadow: 0 12px 24px -4px rgba(0,0,0,0.15);
transform: translateY(-2px);
}
注意:cubic-bezier(0.25, 0.46, 0.45, 0.94) 比 ease 更轻快,避免拖沓感;负的 spread-radius(如 -4px)能抑制阴影横向溢出,防止卡片“变大”。
移动端点击无反应?别信 :hover,用 .is-hovered 类补位
iOS Safari 和多数安卓 WebView 默认不持续激活 :hover,点一次可能生效,再点就失效。这不是 bug,是规范行为——触控设备没有“悬停”概念。
可靠解法只有两个,且必须选其一:
- 把卡片换成语义化
<button type="button" class="card"></button>,加cursor: pointer和outline: none(但保留键盘 focus 样式) - 用 JS 监听
touchstart或pointerdown,动态添加.is-hovered类:element.classList.add('is-hovered') - CSS 中统一写:
.card:hover, .card.is-hovered { ... }
别依赖 @media (hover: hover),iOS 实测多数机型直接忽略它。
深色模式下阴影发灰?别硬编码 rgba 颜色
固定写 rgba(0,0,0,0.2) 在深色背景上会变成一块糊状灰斑,甚至看不见。阴影颜色必须响应系统主题。
现代方案(Chrome 111+ / Safari 16.4+):
.card {
--shadow-color: color-mix(in srgb, black 12%, transparent);
}
@media (prefers-color-scheme: dark) {
.card {
--shadow-color: color-mix(in srgb, white 8%, transparent);
}
}
.card:hover {
box-shadow: 0 12px 24px -4px var(--shadow-color);
}
兼容老浏览器就退回到媒体查询切换整套 box-shadow 值,但注意:所有数值保持整数(12px,非 12.5px),高 DPI 屏幕对小数像素极其敏感,容易模糊抖动。
最难调的从来不是参数,而是偏移量之间的比例关系:比如 translateY(-2px) 对应 box-shadow 的 offset-y: 12px,差一点,就只是“动了”,不是“浮起来了”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











