%占位符不生成CSS,仅被@extend时激活合并——因其不输出冗余规则、需顶层定义、禁嵌套、不可插值、不可单独使用,适合纯视觉契约类抽象;含参数或响应式逻辑时应改用@mixin。

占位符选择器(%开头)本身不输出 CSS,只在被 @extend 时才“激活”并合并进目标选择器——这是它减少重复的底层机制,但用错位置或嵌套方式,反而会让样式消失或失控。
为什么%placeholder不会生成冗余CSS
占位符不是真实类名,Sass 编译器默认跳过它,除非有 @extend 显式引用。比如:
%sr-only {
position: absolute;
width: 1px;
height: 1px;
}
.visually-hidden {
@extend %sr-only;
}
最终只输出 .visually-hidden 一条规则,不会多出 %sr-only 的空声明。而如果写成 .sr-only 类再被 @extend,它本身就会出现在 CSS 里,造成冗余。
- 必须用
%开头,不能带插值:%u-mt-#{$n}会报错 “%placeholderis not a valid selector” - 不能单独出现在 HTML 中:
<div class="sr-only"> 没用,必须是 <code><div class="visually-hidden"> <li>跨文件使用时,必须先 <code>@use或@forward导入,否则@extend找不到 - 用
%clearfix+@extend:多个组件都@extend %clearfix,最终只有一份 clearfix 规则,选择器列表变长但声明不重复 - 用
@mixin flex-center:每次@include都复制整段display: flex; justify-content: center;,声明重复但选择器干净 - 想复用带响应式逻辑的样式?别用
%——它无法嵌套@media,只能靠@mixin+ 调用方控制断点
@extend %foo 和 @include mixin-foo 的本质区别
@extend 是选择器合并,@include 是样式复制。前者生成更短的 CSS 文件(尤其适合工具类),后者更灵活(支持参数、计算、媒体查询)。
立即学习“前端免费学习笔记(深入)”;
嵌套定义%会导致样式丢失
Sass 不解析嵌套在另一个占位符内部的 %。下面这段代码编译后,%btn-focus 的样式根本不会出现:
%button-base {
color: $text;
%btn-focus { color: $white; } // ❌ 无效:嵌套占位符不被识别
&:focus { @extend %btn-focus; }
}
正确做法是把所有占位符提至顶层:
%button-base {
color: $text;
}
%btn-focus {
color: $white;
}
.btn {
@extend %button-base;
&:focus { @extend %btn-focus; }
}
- 每个
%必须独立存在于文件顶层作用域 - 嵌套结构里只能用
&拼接,不能靠嵌套定义新占位符 - VS Code 全局搜索
%能快速发现是否误嵌套
哪些场景该优先用%而不是@mixin
占位符适合「纯视觉契约」且「永不单独存在」的抽象规则,比如重置、可访问性、布局基底。它不接受参数,也不参与计算,所以边界必须清晰。
- ✅ 推荐:
%sr-only、%clearfix、%reset-list、%visually-hidden - ❌ 避免:
%button(应拆成%btn-base+%btn-size+%btn-theme)、%card-shadow(带变量计算的应改用@mixin) - ⚠️ 注意:
@extend后的选择器长度会增长,比如.header .nav .item:hover@extend %btn-focus,可能触发浏览器选择器性能警告
真正难的是判断“这个抽象值要不要参数化”——一旦需要 $color 或 $size,就该立刻切到 @mixin,别硬塞进 % 里。


















