SCSS 的 @extend 是编译期选择器合并机制,非体积优化工具;它拼接选择器而不共享声明,易致CSS体积增大、选择器爆炸、权重失控,仅 %sr-only 等无副作用占位符安全可用,推荐改用 @mixin 或 CSS 自定义属性实现声明复用。

SCSS 的 @extend 不是“节省体积”的工具,而是编译期选择器合并机制;它在多数工程场景下直接导致 CSS 体积增大、选择器爆炸、权重失控——除非你严格限定使用边界。
为什么 @extend 编译后 CSS 反而变大
它不共享声明,只拼接选择器。比如 %button-base 被 .btn-primary 和 .btn-secondary 同时 @extend,输出就是两套完全相同的声明块,而非一份声明被两个选择器共用。
- 浏览器无法合并不同选择器下的相同样式(
cssnano也做不到) - 搜索
margin: 0.5rem在输出 CSS 中出现 37 次?基本可判定是@extend泛滥 - gzip 后体积仍超标,说明冗余在内容层,不是格式层
哪些 %placeholder 真的安全可用
仅当满足「挂到任意 HTML 元素上都 100% 有效且无副作用」时,才考虑用 @extend。这不是风格偏好,是硬性校验标准。
- 能用:
%sr-only、%visually-hidden、%reset-list—— 它们不含伪类、无媒体查询、不依赖父级结构、不随主题变量变化 - 不能用:
%btn-hover(含:hover)、%md\:flex(含媒体查询)、%card-header(隐含.card > &结构) - 一个快速验证法:把占位符名改成真实类(如
.sr-only),直接加到<div> 上,看是否正常工作且不影响其他样式<h3>替代方案比“适度使用”更实际</h3> <p>所谓“适度”,在协作项目中极易滑坡。真正可控的路径是切换抽象层级:从“选择器复用”转向“声明复用”或“逻辑复用”。</p> <p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p> <ul> <li>用 <code>@mixin封装带参数的样式逻辑:@mixin spacing($size) { margin: $size * 0.25rem; },不同调用生成不同值,天然去重 - 用 CSS 自定义属性统一视觉契约:
.component { --spacing-sm: 0.5rem; margin: var(--spacing-sm); },修改变量即全局生效 - 禁用跨文件
@extend:Dart Sass 7.0+ 默认模块隔离,@use未显式暴露的%placeholder会被静默忽略,导致样式缺失却难以定位 - 用 Stylelint 规则
scss/no-extend全局禁止,只对白名单项(如%sr-only)例外放行
最常被忽略的一点:选择器爆炸往往不是因为用了太多 @extend,而是本该拆成两个独立 class 的职责,被强行用嵌套 + @extend 绑在一起了——这时删掉 @extend,反而让结构更清晰。


















