.card:hover动画需四步:显式声明transition(如background-color和box-shadow)、提升选择器权重(如.card-hoverable:hover)、避免祖先overflow:hidden裁剪阴影、移动端补:active或JS交互。

直接加 .card:hover { background-color: #f8f9fa; box-shadow: 0 0.5rem 1rem rgba(0,0,0,.15); } 不会动——缺过渡、被覆盖、父容器裁剪、移动端不触发,四个环节漏一个就白写。
必须显式声明 transition 才能动
transition 不是可选配置,是动画生效的前提。Bootstrap 5 的 .card 默认没写它,哪怕你写了 hover 状态,浏览器也不会“滑动”变色或投影。
- 在
.card常态规则里加:transition: background-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out; - 别用
transition: all——它会把border、outline甚至margin变化也纳入过渡,干扰焦点感知 - 如果只要背景渐变,而投影是“开/关”式切换(非渐进加深),可只过渡
background-color,投影用box-shadow: 0 0 0 transparent初始值保兼容
选择器权重不够时,.card:hover 被默认样式压住
Bootstrap 5 的 .card 自带 background-color: var(--bs-card-bg) 和 box-shadow: 0 0 0 rgba(0,0,0,0),这两条声明优先级高,纯 .card:hover 很可能被覆盖。
- 调试阶段可用
!important快速验证是否为权重问题:.card:hover { background-color: #e9ecef !important; box-shadow: 0 0.5rem 1rem rgba(0,0,0,.15) !important; } - 上线前务必改用更具体选择器,例如:
.card.card-hoverable:hover,并在 HTML 中加class="card-hoverable" - 若卡片在
.card-group内,它自带overflow: hidden,会直接砍掉投影——此时再高的选择器权重也没用
overflow: hidden 是阴影消失最常被忽略的原因
box-shadow 绘制在盒模型外部,只要祖先元素设了 overflow: hidden(比如 .row、.container-fluid、自定义 wrapper),阴影就会被硬裁切,和 CSS 权重无关。
- 看阴影是否刚好卡在 outline 边上,就能快速判断是不是这个原因
- 稳妥解法:删掉或改为
overflow: visible;若结构受限,给.card加position: relative; z-index: 1;,并确认无兄弟元素用更高z-index盖住它 - 特别注意
.card-group——它内部强制overflow: hidden,想保留阴影就得换布局,用.row + .col或 Flex 容器替代
移动端真机点按不触发 :hover,纯 CSS 方案不可靠
iOS Safari 和 Android Chrome 在真实设备上,单次点击不会触发 :hover,这是规范行为,不是 bug。如果你依赖“点一下变色+投影”来暗示可交互,得补逻辑。
- 加
:active规则模拟按下反馈:.card:active { transform: scale(0.98); }(注意是缩小,不是放大) - 或用 JS 监听
touchstart/touchend切换 class:card.addEventListener('touchstart', () => card.classList.add('touched')) - 别混用
:hover和:active同时缩放,否则触屏用户点一下就卡住
真正容易被忽略的是:过渡动画本身不受深色模式影响,但颜色值选错,再顺滑也白搭;overflow: hidden 裁剪阴影的问题,在开发者工具里根本看不出,必须真机测。









