%placeholder配合@extend是唯一真正压缩CSS体积的复用方式,因占位符不输出CSS且自动合并相同声明;继承普通类名会残留空规则、拖入伪类,嵌套或跨文件误用则导致冗余或编译失败。

直接用 %placeholder 配合 @extend,是 Sass 中唯一能真正压缩最终 CSS 体积的复用方式;其他写法——包括继承普通类名、嵌套定义占位符、跨文件未正确引入——都会让 CSS 更臃肿或编译失败。
为什么 %reset-list 比 .reset-list 更省体积
占位符以 % 开头,编译后完全不输出任何 CSS 规则;而普通类名哪怕没人 @extend,也会原样出现在最终 CSS 里。更关键的是:@extend %reset-list 会让所有调用它的选择器合并成一条规则,比如 .nav-menu, .sidebar-list { margin: 0; padding: 0; list-style: none; };但 @extend .reset-list 会保留 .reset-list 自身那条空规则,还可能把它的伪类(如 .reset-list:hover)一并拖进来。
-
%reset-list是纯骨架,只供继承,不会泄漏到 HTML 或浏览器中 - 一个
%可被多次@extend,Sass 会自动合并相同声明,避免重复输出 - 别在 HTML 里写
class="%reset-list"——它根本不会生效,也不该出现
@extend %text-muted 在嵌套结构里为何没效果
@extend 只作用于当前选择器本身,不穿透嵌套层级。写成 .card { @extend %text-muted; &__header { color: red; } },只有 .card 获得样式,.card__header 不会自动继承。
- 想让子元素也复用,必须显式写
.card__header { @extend %text-muted; } - 不要指望
&拼接后能触发继承,@extend对&__header这种动态拼接无效 - 嵌套越深,越容易误以为“父级继承了,子级就自动有了”,实际完全不是这样
跨文件使用 %button-base 编译报错 “Extending unknown pseudo-class”
Dart Sass v7.0+ 默认禁止隐式跨文件 @extend,% 占位符不会自动暴露到其他文件。路径、顺序、引入方式三者错一个就会报错。
立即学习“前端免费学习笔记(深入)”;
- 推荐写法:
@use "base" as *;后可直接@extend %button-base - 严格作用域写法:
@use "base";后必须写@extend base.%button-base - 检查
@use顺序:定义%的文件必须在引用它的文件之前@use - 禁止循环依赖:A
@useB,B 就不能再@useA
什么时候该放弃 %,改用 @mixin
% 是纯静态复用,零灵活性。只要需求里带“可能变”三个字,就该换 @mixin。
- 需要传参(比如
@mixin text-size($size)) - 要包裹
@media或@supports - 只复用部分属性,而非整块声明(如仅共享
transition,不共享color) - 目标选择器本身含复杂组合器(如
article h2),@extend会照单全收,污染语义
最常被忽略的一点:% 看似省代码,但一旦项目里开始出现条件分支、主题切换、响应式变体,它就成了硬编码陷阱——这时候删掉 % 改用 @mixin,反而更快。


















