正确做法是将悬停逻辑封装为独立混入.card-hover(@lift, @shadow-hover),仅控制transform位移和box-shadow阴影,显式声明transition及z-index:10,并按海拔分档管理阴影值以适配主题切换。

如何用 .card-hover() 封装悬停位移与阴影变化
直接在 .card() 里写 &:hover 会导致所有卡片强制带悬停效果,无法按需关闭。正确做法是把悬停逻辑抽成独立混入,只在需要的地方叠加。
它应该只控制两个属性:位移(transform: translateY())和阴影(box-shadow),不碰背景、圆角或边框——那些属于基础结构职责。
-
.card-hover()必须接收@lift(如-4px)和@shadow-hover(如多层值)两个参数,避免硬编码 - 内部必须显式声明
transition: transform 0.25s ease, box-shadow 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94),不能依赖all - 别漏掉
z-index: 10——否则抬起后可能被兄弟元素遮住,尤其在 Flex/Grid 容器中
为什么 box-shadow 参数必须分层且语义化
写死 box-shadow: 0 8px 24px rgba(0,0,0,0.2) 看似省事,但一到深色模式或主题切换就全崩:透明度太低看不见,太高又发灰;模糊值固定导致小卡片显得虚、大卡片又不够立体。
Less 混入应按 Material Design 的海拔逻辑分档:@shadow-base、@shadow-hover、@shadow-lifted,每档对应一组偏移+模糊+透明度组合,而非单个数值。
- 推荐三档值:
0 2px 4px rgba(0,0,0,0.1)(base)、0 4px 12px rgba(0,0,0,0.15)(hover)、0 12px 24px rgba(0,0,0,0.08)(lifted) - 颜色统一用
fade(#000, 12%)而非rgba(),方便后期替换主题基色 - 别让混入输出
transition——动画时长和缓动函数由调用方决定,混入只管静态样式
过渡动画卡顿?检查 transition 是否误触重排属性
很多人写 transition: all 0.3s ease,结果 hover 时文字突然变淡、边框跳动、甚至滚动条抖动——根本不是阴影问题,而是 all 把 opacity、border-color、font-size 全拖进动画队列了。
真正需要过渡的只有两个:位移(transform)和阴影(box-shadow)。其他任何属性加入都会增加渲染压力,尤其在低端安卓 WebView 或旧版 Safari 中明显卡顿。
- 必须写成
transition: transform 0.25s ease, box-shadow 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94) - 进出场节奏要不同:hover 进入快一点(
cubic-bezier(0.25, 0.46, 0.45, 0.94)),移出稍缓(可不设,靠浏览器默认反向) - 移动端无 hover,加
@media (hover: hover) { .card:hover { ... } }防止 iPad 上误触发
父容器裁切阴影?优先排查 stacking context
卡片 hover 抬起后阴影一半消失,90% 是父容器悄悄创建了局部 stacking context,不是阴影值写错了。常见诱因:父级有 overflow: hidden、transform、opacity 或 filter。
别急着改 box-shadow 值,先确认渲染层级是否被截断。最稳妥的解法是让卡片脱离父级 stacking context 影响,而不是硬调阴影扩散半径。
- 给卡片加
position: relative; z-index: 10;是基础操作,但不够 - 如果父容器必须保留
overflow: hidden,改用伪元素::after绘制阴影并设position: absolute; top: 0; left: 0; - 慎用
will-change: transform——只对高频悬停卡片启用,否则会提前占用 GPU 内存










