长阴影本质是多层box-shadow叠加,通过Sass@for循环生成逐层偏移的硬边阴影,支持方向、层数和间距自定义,并需注意透明度衰减与性能优化。

长阴影的本质是多层 box-shadow 叠加
长阴影不是某种独立的CSS属性,而是利用 box-shadow 的多重投影能力,让每层阴影在相同方向(比如右下)偏移固定增量,形成视觉上的“拉长”效果。关键在于:必须用逗号分隔多个阴影值,且顺序决定图层堆叠——越靠前的阴影越靠近元素本体,越靠后的越远、越模糊(如果设了模糊半径)。
手动写10层阴影既易错又难维护,所以 Sass 的 @for 循环是最直接的解法。注意:Sass 编译后仍是纯 CSS,不依赖运行时 JS,兼容性等同于 box-shadow 本身(IE9+)。
用 @for 循环生成逐层偏移的 box-shadow
核心逻辑是:每层阴影的水平和垂直偏移量随循环变量线性递增,模糊半径通常保持为 0(否则边缘发虚,失去“硬边长阴影”质感)。下面是一个典型实现:
@function long-shadow($direction: right-bottom, $steps: 10, $offset: 1px) {
$shadows: ();
@if $direction == right-bottom {
@for $i from 1 through $steps {
$shadows: append($shadows, $i * $offset $i * $offset 0 0 rgba(0,0,0,0.1), comma);
}
}
@else if $direction == right {
@for $i from 1 through $steps {
$shadows: append($shadows, $i * $offset 0 0 0 rgba(0,0,0,0.1), comma);
}
}
@return $shadows;
}
<p>.example {
box-shadow: long-shadow(right-bottom, 15, 1px);
}几个要点:
立即学习“前端免费学习笔记(深入)”;
-
$offset控制每层之间的物理距离,1px是常用起点;调大它会让阴影更“疏松”,但可能断裂 -
$steps决定总层数,15–20 层对多数 UI 已足够;超过 30 层可能触发某些浏览器的渲染性能警告 - 返回值必须是空格分隔的列表(
append(..., comma)确保最终输出为逗号分隔字符串) - 函数内不能直接写
box-shadow:,只能返回阴影值列表,由调用处赋给属性
容易被忽略的两个坑:透明度衰减与伪元素替代方案
纯等透明度叠加(如每层都用 rgba(0,0,0,0.1))会导致最终边缘过重。更自然的做法是让透明度随层级衰减:
@for $i from 1 through $steps {
$alpha: 0.1 / $i; // 或用指数衰减:pow(0.9, $i)
$shadows: append($shadows, $i * $offset $i * $offset 0 0 rgba(0,0,0, $alpha), comma);
}另一个现实约束:超多层 box-shadow 在低端设备上可能触发渲染卡顿。若只需静态长阴影(如 logo 文字),用伪元素 + transform: translate() 复制多层更轻量:
.text::before {
content: attr(data-text);
position: absolute;
top: 0; left: 0;
color: #000;
z-index: -1;
transform: translate(1px, 1px);
}——但这就脱离了“单属性控制”的初衷,需按场景权衡。
编译后 CSS 的体积与调试技巧
15 层阴影编译后可能生成 500+ 字符的单行 box-shadow 值,肉眼难以定位某一层是否出错。建议:
- 开发阶段开启 Sass 源码映射(source map),在 DevTools 中点开对应行,能反查到循环变量
$i的值 - 临时把
@for改成@each $i in 1 2 3,缩小范围快速验证逻辑 - 避免在
:hover等动态状态中高频切换大量阴影——重绘成本高,优先考虑transition: box-shadow的缓动而非逐帧生成
真正麻烦的从来不是写循环,而是决定哪一层该停、透明度怎么衰、以及要不要为老设备降级到 5 层。


















