%placeholder编译后完全消失,不生成任何CSS规则;它仅作为样式模板,在@extend调用时将声明内联合并至目标选择器,避免冗余输出和选择器爆炸。

占位符选择器%不输出CSS,只在@extend时内联展开
直接说结论:%placeholder本身编译后完全消失,不会生成任何CSS规则;它只是个“样式模板”,只有被@extend调用时,才把声明(比如display: flex、margin: 0)合并进目标选择器。这和@extend .class有本质区别——后者会复制整个选择器链,导致冗余爆炸。
常见错误现象:写了%reset但没被任何@extend引用,结果编译后啥都没留下,开发者误以为“失效”,转而手动加class="reset",反而增加HTML耦合和类名冗余。
-
%开头是硬性语法要求,写成.reset或reset都无效 - 必须定义在顶层作用域,不能嵌套在
.card { }或@media块里 - 跨文件使用必须显式
@use "base" as *或@use "base"; @extend base.%reset
@extend %placeholder比@mixin更紧凑,但仅限无参、无状态场景
@extend %btn-base会让所有调用者共享一条CSS规则,比如.primary-btn, .secondary-btn { padding: 0.5rem; border-radius: 4px; };而@mixin btn-base每次调用都展开全部样式,容易重复输出相同声明。
但这只在“完全一致复用”时成立。一旦涉及参数、伪类或媒体查询,%就失效了:
立即学习“前端免费学习笔记(深入)”;
-
%btn-base:hover语法错误,Sass直接报错 -
%sm-only不能写在@media块内,否则编译失败 - 需要传
$size或$color?必须用@mixin,%不支持传参
能安全用%的典型例子:%sr-only、%truncate、%clearfix——它们不依赖上下文、无交互状态、可直接加到HTML上100%生效。
滥用@extend .class会导致选择器爆炸和体积反增
很多人以为@extend .btn-base能减体积,结果编译出.btn, button.btn, [type="submit"].btn, .card .btn, .modal .btn这种超长逗号列表。这不是bug,是Sass的设计逻辑:它机械拼接所有匹配的选择器,不判断是否真实使用。
后果很实在:
- gzip压缩率下降:cssnano无法合并不同规则块里的相同样式
- 触发IE 4095字符限制(老项目仍需兼容)
- 生成
.card .btn-primary这种组合选择器,但HTML里可能根本没这种结构
检查方法:构建后搜索font-weight: 600,如果结果数远大于你写的类数,基本就是@extend泛滥了。
真正可控的优化路径是% + @mixin + 严格边界
别纠结“哪个更好”,关键看你要复用的是什么:
- 用
%:仅限语义清晰、永不单独存在、无参数、不含:hover或@media的原子功能类 - 用
@mixin:只要带颜色、尺寸、断点、状态变化(&:hover)、或动态计算(lighten($color, 10%)) - 混用要警惕:
%button-base里写了&:hover,被.btn和.btn-outline同时@extend,就会把:hover逻辑污染到所有调用处
最容易被忽略的是:占位符本身不参与浏览器样式计算,DOM里查不到它,DevTools里也看不到它——它只活在编译期。这种“存在即不可见”的特性,才是它成为体积优化隐形引擎的关键。









