@extend %placeholder 能减少 css 行数,因编译时合并所有继承它的选择器为一条规则,避免重复声明;占位符本身不输出 css,仅被调用时参与编译,且必须顶层定义、显式引入、不可嵌套或置于媒体查询内。

% 占位符本身不输出任何 CSS,只有被 @extend 调用时才参与编译;直接 @extend .btn 反而会让 CSS 体积变大,真正能压缩输出的,是 %button-base + @extend %button-base 的组合,但必须满足扁平命名、无嵌套定义、跨文件显式引入三个前提。
为什么 @extend %placeholder 能减少最终 CSS 行数
SCSS 编译时把所有 @extend %placeholder 的选择器合并成一条规则,而不是复制样式块。比如 .primary-btn 和 .secondary-btn 都 @extend %btn-base,最终只生成:
.primary-btn, .secondary-btn { padding: 8px 16px; border-radius: 4px; }
而如果用 @mixin btn-base,每次 @include 都会完整展开一遍,重复输出相同声明。
-
%开头的占位符在编译后彻底消失,不占用字节 - 普通类名(如
.btn)哪怕没人用,也会原样输出到 CSS 中 - 若占位符含
&:hover,所有继承它的选择器都会生成对应伪类,慎用
% 占位符不能嵌套定义,也不能放在 @media 里
写成 .card { %base { ... } } 或 @media (min-width: 768px) { %responsive { ... } } 都会导致编译失败或行为异常。
-
%必须定义在顶层作用域(即不能缩进,不能包在其他选择器或 at-rule 内) - 嵌套内定义的占位符,Sass 会尝试拼接父路径,产出类似
.card .card__title这种冗余选择器 -
@media内定义的%会被限制在该媒体查询作用域,外部@extend会报Extending unknown pseudo-class "%xxx"
跨文件使用 % 占位符必须显式 @use
Dart Sass v7.0+ 默认禁止隐式跨文件继承,@import 已不推荐,@use 是唯一可靠方式。
- 用
@use "base" as *后,可直接写@extend %reset-text - 用
@use "base"(不加as *),则必须写@extend base.%reset-text - A 文件
@use "B",B 文件就不能再@use "A",否则循环依赖,编译中断 - 报错
Extending unknown pseudo-class时,优先检查@use路径是否拼错、顺序是否颠倒
@extend 不穿透嵌套层级,子元素要单独继承
@extend 永远只作用于当前选择器本身,不会自动影响其子元素。
- 写
.card { @extend %bordered; &__header { color: red; } },只有.card获得边框样式,.card__header不会 - 想让子元素也应用同一套基础样式,必须显式写
.card__header { @extend %text-muted; } - 不要指望
&__body { @extend %padding-sm; }这种写法能“继承”父级的占位符逻辑——它只是语法上合法,语义上无效
最容易被忽略的是:占位符必须被至少一个 @extend 调用,否则它在编译后完全不存在,连 debug 都找不到痕迹;另外,% 适合抽象视觉原子(如 %sr-only、%clearfix),一旦混入布局属性(margin、display、position),就极易在不同上下文中被迫覆盖,反而增加 !important 和调试成本。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











