%placeholder不生成CSS,仅被@extend时内联展开;而@extend .class会复制整个选择器链,导致冗余和爆炸。核心在于:%placeholder声明只合并样式值,不输出选择器,体积更小、无污染、无 specificity 冲突。

占位符选择器 %placeholder 不生成实际 CSS,而类继承 @extend .class 会复制选择器链——这是体积差异的根本原因。
为什么 @extend %btn-base 比 @extend .btn-base 更省体积
核心区别在输出行为:
-
@extend %btn-base:只把%btn-base内的声明(如padding: 12px)合并进调用者,最终 CSS 中完全不出现%btn-base这个选择器 -
@extend .btn-base:会把所有定义.btn-base的选择器(比如button.btn-base、.btn.btn-base、[type="submit"].btn-base)全部复制到每个 extend 它的地方,极易造成选择器爆炸 - 若
.btn-base自身带伪类(如.btn-base:hover),这些也会被复制,可能污染其他组件的 :hover 行为
%placeholder 必须写对位置,否则等于没写
占位符不是“写了就能用”,它必须满足三个硬性条件才能生效:
- 必须定义在顶层作用域(不能嵌套在
.card { ... }或@media块里) - 不能用变量拼接名,
%#{$name}直接报错,Sass 不支持动态占位符 - 跨文件使用时,必须显式
@use "path/to/file" as *或@use "path/to/file"后写@extend file.%reset;仅@use "vars"不够
媒体查询里 @extend %placeholder 失效?不是 bug,是设计限制
Sass 的 @extend 在编译期解析,而媒体查询是运行时逻辑。因此:
立即学习“前端免费学习笔记(深入)”;
-
@media (min-width: 768px) { .btn-lg { @extend %btn-base; } }—— 这段代码会报错 - 解决方案只有两种:把占位符定义移到顶层,并在媒体查询外提前 extend;或改用
@mixin+@include(它支持在媒体查询内调用) - 链式
@extend(A → B → C)按源码顺序合并,但一旦中间某层在@media里定义,整条链就断开
体积优化效果不是理论值,而是可测量的
在中大型项目中,滥用 @extend .class 导致未使用 CSS 占比常达 30%–50%;而严格用 %placeholder 替代后:
- 编译产物里不会多出任何占位符对应的选择器,CSS 文件体积直降
- 避免了因选择器复制引发的 specificity 冲突,减少靠
!important补救的 hack 代码 - 配合
clean-css压缩时,更少的初始规则数 = 更高的压缩率
真正容易被忽略的是:占位符本身不参与样式计算,也不触发浏览器重排重绘——它只是编译期的“样式模板”,连 DOM 查询都找不到它。这种“存在即不可见”的特性,才是它成为体积优化隐形引擎的关键。


















