直接用box-shadow写多层阴影易出错,因手动拼接易漏逗号、错单位、混用inset,响应式与语义化需求使硬编码维护成本陡增;应改用参数化.mixin封装层级与上下文逻辑。

为什么直接用 box-shadow 写多层阴影容易出错
Less 里写多层 box-shadow 时,手动拼字符串极易漏逗号、错单位、混用 inset,尤其当需要响应式层级(比如 shadow-2 在移动端降为 shadow-1)时,维护成本陡增。更麻烦的是,不同组件对阴影的语义需求不同——按钮要「浮起感」,卡片要「悬浮深度」,模态框要「背景压暗+边缘柔化」,硬编码值会让后续调整变成全局搜索替换。
用参数化混合(.shadow())替代固定值
核心是把阴影拆解为「层级索引」和「上下文变量」:层级决定基础偏移/模糊/色值,上下文(如 @surface、@elevation)决定是否启用内阴影、是否叠加蒙层。示例:
.shadow(@level: 1, @context: default) when (@context = default) {
@offset: unit(@level * 2, px);
@blur: unit(@level * 8, px);
@color: rgba(0, 0, 0, 0.1 * @level);
box-shadow: @offset @offset @blur @color;
}
<p>.shadow(@level: 1, @context: card) {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.06);
}</p>
关键点:
-
@level不直接对应像素,而是设计系统中的抽象层级(如 1=轻微浮起,3=强悬浮),避免数值魔数 -
@context用字符串区分语义场景,比写一堆.shadow-card()、.shadow-btn()更易扩展 - 用
when条件分支控制逻辑,而非嵌套if,Less 编译更稳定
如何让阴影适配深色模式与高对比度
纯 rgba(0,0,0,.1) 在深色背景下会失效,必须动态计算。Less 本身不支持颜色模式检测,所以得靠 CSS 自定义属性桥接:
:root {
--shadow-color: rgba(0, 0, 0, 0.1);
}
<p>@media (prefers-color-scheme: dark) {
:root {
--shadow-color: rgba(255, 255, 255, 0.08);
}
}</p><p>.shadow-dark-friendly(@level: 1) {
box-shadow: 0 unit(@level <em> 2, px) unit(@level </em> 8, px) var(--shadow-color);
}</p>
注意:
- 不能在 Less 中用
lighten()或darken()动态生成深色阴影——它们在编译期就固化了,无法响应用户系统设置 -
var(--shadow-color)必须配合:root声明,否则 Less 编译会报variable is undefined - 高对比度模式下,部分浏览器会忽略
box-shadow,需额外加outline或边框模拟视觉层次
避免混合命名污染与作用域泄漏
直接定义 .shadow() 会导致全局命名冲突(尤其团队协作时)。正确做法:
- 用命名空间包裹:
.elevation { .shadow(...) { ... } },调用时写.elevation > .shadow(2); - 所有参数设默认值,且默认值用
@变量声明在顶部,方便统一管理(如@shadow-base-opacity: 0.08;) - 禁用
!important—— 它会破坏 CSS 层叠,调试时根本分不清是哪个混合注入的样式 - 如果项目用 Webpack,确保
less-loader的math选项设为always,否则@level * 2这类运算可能不生效
真正难的不是写出五层阴影,而是让设计师改一次「层级 3 的模糊度从 24px 降到 20px」时,你不用打开七个文件去替换数字。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











