占位符选择器%不输出CSS,仅被@extend调用时合并样式;它非类名非变量,是抽象“样式钩子”,未被引用则完全不编译;含伪类、@media、参数或跨文件未正确@use时均失效。

占位符选择器%本身不输出任何 CSS,只在被@extend调用时把样式声明内联合并进目标选择器——这是它优化体积的唯一机制,也是所有误用的根源。
为什么%placeholder编译后完全消失?
它不是类名,也不是变量,是纯抽象的“样式钩子”。Sass 编译器遇到%reset这种定义,直接跳过生成 CSS 规则;只有碰到@extend %reset时,才把margin: 0; line-height: 1;这类声明,原样塞进当前选择器的规则块里。
- 写
%sr-only但没被任何@extend引用?编译后啥都没有,不是失效,是根本没触发 - 写成
.sr-only或sr-only?语法错误,Sass 直接报错Invalid selector - 定义在
@media块里?外部@extend会报Extending unknown pseudo-class "%xxx"
@extend %btn-base比@extend .btn-base更省体积?
是,但仅当.btn-base本身不含伪类、无嵌套、且你不需要它单独存在时成立。
-
@extend %btn-base→ 编译出.primary-btn, .secondary-btn { padding: 0.5rem; }(一条规则) -
@extend .btn-base→ 编译出.btn-base { padding: 0.5rem; }+.primary-btn, .secondary-btn { padding: 0.5rem; }(两条,且.btn-base:hover可能也被拖进来) - 如果
.btn-base定义了&:hover,而你只想要基础 padding,@extend %btn-base能干净避开
哪些场景必须放弃%,改用@mixin?
只要出现以下任一条件,%就失效,硬上只会埋坑:
- 需要传参:
%rounded($radius)语法非法,必须用@mixin rounded($radius) - 含
:hover、:focus等伪类:%btn-base:hover直接报错 - 要嵌套在
@media里:@media (max-width: 768px) { %sm-only { ... } }编译失败 - 只复用部分属性(比如只要
display: flex不要margin):%只能全量继承,没法拆
跨文件使用%时最常踩的坑
Dart Sass v7.0+ 默认禁用隐式跨文件@extend,不是配置问题,是模块隔离变严了。
- 定义在
_base.scss里的%clearfix,在_card.scss中不能直接@extend %clearfix - 正确做法:在
_card.scss开头加@use "base" as *;(全局引入),或@use "base";后写@extend base.%clearfix - 循环依赖:
A @use B且B @use A?编译直接中断,!optional掩盖不了 - 路径写错或
@use顺序颠倒?报错Undefined placeholder selector "%xxx",别急着加!optional
真正可控的优化不在“多用%”,而在清楚知道哪条样式链必须原子化静默(用%),哪条必须动态可变(用@mixin),以及哪条根本不该复用(直接写死)。一个%定义是否安全,三秒就能判断:它有没有:、有没有@media、有没有参数、有没有被@use正确暴露——漏掉任意一条,后续压缩、调试、维护都会卡住。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











