CSS box-shadow:8 种现成可抄的阴影 + 那些性能坑
不是讲 4 个参数怎么写——是给你 8 段直接能用的代码,每个旁边显示真实渲染效果,再讲一下移动端滚动掉帧的修复方法。看完直接复制走。
语法 30 秒回忆
box-shadow: [inset] X Y blur spread color;
inset— 加了就是内阴影X / Y— 偏移方向(正向 = 右/下)blur— 模糊半径,越大越软spread— 扩散半径,正值扩大、负值收缩color— 总是用rgba(),方便调透明度
8 种现成阴影
1. 柔和阴影(最常用)
box-shadow: 0 4px 12px rgba(0,0,0,.10);
卡片、弹窗的"默认值"。偏移小、模糊大、透明度低。看起来像浮在桌面上很轻一点点。
2. 浮起感(hover 状态常用)
box-shadow: 0 12px 28px -8px rgba(0,0,0,.20);
spread 取负值让阴影向中间收紧,看起来物体离地更高。配 transition 做 hover 动效。
3. 硬边阴影(粗野/像素风)
box-shadow: 4px 4px 0 rgba(0,0,0,.30);
模糊 = 0,硬边偏移。NeoBrutalism 风格基础。最近 Tailwind 项目里特别多。
4. 凹陷感(按下/输入框)
box-shadow: inset 0 2px 4px rgba(0,0,0,.15);
按钮 active 态、输入框 focused 态。让用户视觉感受到"凹下去了"。
5. 霓虹光效(暗色模式好看)
box-shadow: 0 0 24px 4px rgba(99,102,241,.6);
偏移全 0,纯模糊 + 扩散 + 品牌色。亮色背景下太张扬;暗色模式或 dashboard 场景下效果惊艳。
6. 多层叠加(Material 风)
box-shadow: 0 1px 2px rgba(0,0,0,.07), 0 4px 8px rgba(0,0,0,.05), 0 12px 24px rgba(0,0,0,.03);
三层不同 blur 的阴影叠加,更接近真实世界的光线衰减。比单层柔和阴影"更高级"。
7. 替代 border(focus ring)
box-shadow: 0 0 0 2px rgba(99,102,241,.5);
用 spread 做"伪边框"。关键好处:不占布局空间,不会让元素尺寸变化。focus / selected 状态用这个比加 border 流畅得多。
8. 双向内阴影(凹陷浮雕)
box-shadow: inset 0 2px 4px rgba(0,0,0,.15), inset 0 -1px 2px rgba(255,255,255,.6);
上深下亮,模拟"凿进去"的视觉。复古 skeuomorphism 设计、3D 卡片返潮时常见。
box-shadow vs filter: drop-shadow
这是面试题里常考但实际开发也容易搞混的:
| 对比 | box-shadow | filter: drop-shadow |
|---|---|---|
| 作用对象 | 盒子边界(矩形 / border-radius) | 元素的不透明像素 |
| 透明 PNG / SVG | 沿矩形外框投影 | 沿不透明形状投影 |
| 支持 inset | 是 | 否 |
| 性能 | 更快(合成层友好) | 稍慢(光栅化) |
| 典型场景 | 卡片、按钮、容器 | 带透明区域的图标/插画 |
简单记:矩形 + 圆角 → box-shadow;不规则形状 → drop-shadow。
移动端性能坑
大面积阴影 + 列表滚动 + 中低端机 = 掉帧。原因是 box-shadow 触发新的 GPU 合成层,列表项越多合成开销越大。
/* 错误:每个列表项都来个 multi-layer 多层阴影 */
.list-item {
box-shadow:
0 1px 2px rgba(0,0,0,.07),
0 4px 8px rgba(0,0,0,.05),
0 12px 24px rgba(0,0,0,.03);
}
/* 正确:列表项用简单阴影;hover/active 时才升级 */
.list-item {
box-shadow: 0 1px 3px rgba(0,0,0,.08);
transition: box-shadow .2s;
}
.list-item:hover {
box-shadow: 0 4px 12px rgba(0,0,0,.12);
}
真实事故:电商商品列表卡顿。Devtools Performance 一看,30% 时间在 Composite Layers。原因是每个商品卡片有 3 层 box-shadow,长列表 200+ 个商品同时合成。改成单层 + 滚停时才升级,FPS 从 32 回到 58。
动效中过渡阴影的"正确"姿势
.card {
/* 把阴影初始值写好,避免从 "none" 到 "0 4px 12px..." 的不流畅过渡 */
box-shadow: 0 0 0 rgba(0,0,0,0);
transition: box-shadow .25s ease, transform .25s ease;
}
.card:hover {
box-shadow: 0 8px 24px rgba(0,0,0,.15);
transform: translateY(-2px);
}
多个属性一起动用 transform: translateY 比 top 高效(不触发 layout)。
暗色模式下调整阴影
同一个阴影值在亮色和暗色下视觉效果差很多——暗色背景上轻阴影几乎看不见。两种解法:
/* 方案 A:暗色下加深阴影 + 加白色高光 */
.card { box-shadow: 0 4px 12px rgba(0,0,0,.10); }
@media (prefers-color-scheme: dark) {
.card {
box-shadow:
0 4px 16px rgba(0,0,0,.50),
0 0 0 1px rgba(255,255,255,.05); /* 微高光定义边界 */
}
}
/* 方案 B:暗色下用品牌色发光(适合 dashboard) */
@media (prefers-color-scheme: dark) {
.card:hover {
box-shadow: 0 0 24px rgba(99,102,241,.3);
}
}
不想算 X/Y/blur?CSS box-shadow 可视化工具拖滑块实时预览,直接复制 CSS。
常见疑问
border-radius 之外的阴影会被截掉吗?
不会。box-shadow 沿 border 外缘投射,会跟着 border-radius 走弧度,但: overflow:hidden 不会裁剪外阴影(外阴影不在元素 box 内);裁剪内阴影也需要靠 overflow:hidden。
阴影颜色用半透明黑还是带色调?
取决于设计语言。简洁/中性风用 rgba(0,0,0,0.X)。彩色设计系统(比如 Stripe)会用带轻微品牌色调的阴影:rgba(50,50,93,0.1)——视觉上更"奢华"。