
伪元素 ::before 和 ::after 怎么配合实现带偏移的关联阴影
真实阴影不是均匀包裹卡片的,而是从卡片底部边缘“延伸”出来、略带偏移和模糊的视觉效果。用 box-shadow 单独做,很难模拟这种「贴地感」和「方向性」;而用两个伪元素分别控制「主投影」和「接触阴影」,才能让阴影看起来是从卡片底下自然透出来的。
关键思路是:::before 做一个宽高略大于卡片、轻微缩放+模糊+透明度低的深色层,作为基础投影;::after 做一个极窄(甚至只有 2–4px 高)、完全不模糊、贴近底部边缘的深色条,模拟卡片与背景接触时的压暗区域。
-
::before设置transform: scale(0.96)+filter: blur(12px)+opacity: 0.18,位置固定在卡片下方(top: 100%+margin-top: 8px) -
::after不缩放、不模糊,height: 3px,background: rgba(0,0,0,0.12),同样top: 100%但margin-top: 0,紧贴卡片底边 - 两个伪元素都需设
content: ""、position: absolute,且父容器必须是position: relative
为什么不能只用 box-shadow 的多个值来模拟
多层 box-shadow 确实能堆出类似效果,但存在三个硬伤:投影始终以元素中心为基准发散、无法独立控制「接触区」的形状、在缩放或 transform 动画中会失真(比如卡片 hover 放大时,阴影不会同步「贴地收缩」)。
- 单靠
box-shadow: 0 12px 24px rgba(0,0,0,0.15), 0 4px 8px rgba(0,0,0,0.08)只能做出「浮空感」,缺乏地面接触反馈 - 当卡片加了
transform: translateY(-4px)悬停上浮时,box-shadow的偏移量不会自动补偿,阴影会“卡在原地”,显得脱离 - 伪元素方案中,
::before和::after的top: 100%是相对于当前卡片位置计算的,动画时自动跟随
兼容性和性能要注意什么
所有现代浏览器都支持 ::before/::after + transform + filter,但 filter: blur() 在旧版 Safari(box-shadow,或把 blur() 换成更大范围的 box-shadow 模拟。
立即学习“前端免费学习笔记(深入)”;
- 避免对伪元素使用
transition: all—— 改变filter或transform时,应显式写成transition: transform 0.3s, filter 0.3s - 伪元素层级要确保在卡片下方:
z-index: -1(注意不是z-index: 0,否则可能遮挡内容) - 移动端视口缩放时,
blur(12px)可能显得过重,建议用rem或vw单位控制模糊半径,如filter: blur(0.75vw)
常见错误:阴影没显示 / 卡片被遮挡 / 动画卡顿
伪元素阴影失效,90% 是因为父容器没设 position: relative,导致 absolute 定位脱出上下文;剩下 10% 是 z-index 层级错乱或 overflow: hidden 裁剪了伪元素。
- 检查父卡片是否漏了
position: relative—— 这是最常被忽略的前提 - 确认伪元素的
width/height是否为100%(::before)或明确设值(::after),否则缩放后可能不可见 - 如果卡片用了
overflow: hidden(比如圆角裁剪),需给伪元素加pointer-events: none并确保其不超出父容器边界,或改用clip-path替代 - 动画卡顿时,禁用
will-change: transform(仅在必要时加,且 hover 后及时清除)
px 的模糊更关键。










