%占位符+@extend可压缩CSS体积,但须满足扁平命名、顶层定义、跨文件显式引入三条件;因%不输出CSS、仅被@extend时内联合并,而@extend普通类会复制祖先链并残留空规则,导致选择器爆炸和冗余。

直接用 @extend 普通类名(比如 .btn)不仅不能减少重复,反而会让 CSS 体积变大、选择器失控;真正能压缩输出的,是 % 占位符 + @extend 的组合,但必须满足三个硬条件:扁平命名、顶层定义、跨文件显式引入。
为什么 @extend .class 反而增大 CSS 体积
它不是复用样式,而是把所有引用它的选择器“合并进”被继承类的规则里。一旦多个组件都 @extend .text-center,而 .text-center 本身来自 .utility .text-center 这种嵌套路径,Sass 就会忠实生成 .utility .text-center, .header-btn, .sidebar-btn, .modal-btn —— 每个地方都拖着完整祖先链。
-
.text-center自身那条空规则也会原样输出,白白占体积 - 如果
.text-center含&:hover,所有继承者都会被塞进:hover规则,造成冗余伪类 - 编译后出现超长逗号列表(如
.a, .b, .c, .d, .e, .f {}),可能触发 IE 的 4095 字符限制
%placeholder 必须顶层定义且不嵌套
占位符只在被 @extend 时激活,本身不输出任何 CSS;但它对位置极其敏感:不能写在 @media 块里,不能写在嵌套选择器内部,也不能带插值(如 %u-mt-#{$n} 会报错)。
- 错误写法:
.card { %bordered { border: 1px solid #ccc; } }→ 编译后%bordered样式丢失 - 错误写法:
@media (min-width: 768px) { %responsive { font-size: 1.2rem; } }→ 外部@extend %responsive报错Extending unknown pseudo-class "%responsive" - 正确写法:所有
%必须放在文件最外层,且在@extend语句之前声明
跨文件使用 % 必须显式 @use
Dart Sass v7.0+ 默认禁用隐式跨文件 @extend,% 不会自动暴露。如果你把 %reset-text 定义在 _base.scss,却在 _card.scss 里直接写 @extend %reset-text,编译直接失败。
- 正确方式一:
@use "base" as *;然后@extend %reset-text - 正确方式二:
@use "base";然后@extend base.%reset-text - 禁止循环依赖:
A.scss@use "B",则B.scss不能再@use "A" - 顺序不能错:被
@use的文件必须在引用它的文件之前加载
什么时候该立刻放弃 @extend %,改用 @mixin
@extend 是选择器合并机制,不是样式继承工具。只要涉及以下任一情况,它就不再适用:
- 需要传参(比如颜色、尺寸、断点)→
@mixin btn($color)才能动态计算 - 要嵌套
@media或&:hover→%无法定义响应式逻辑 - 只想复用部分属性(如只要
display和vertical-align,不要margin)→@extend是全量继承,没法选 - 项目用 BEM 或 CSS Modules →
@extend会强行合并.card__title和.list__item-title,破坏命名空间
最容易被忽略的一点是:@extend 不改变选择器权重,也不支持运行时计算——它只是编译时机械拼接。你写的 @extend %button-base,最终生成的选择器权重还是单类级别,压不住 #header .btn 这类高权重要求。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











