mixins是“复制粘贴”式展开,每次调用生成独立规则;extend是“合并选择器”,将调用方追加至被继承类的选择器列表,生成联合声明,减少冗余。

生成的 CSS 选择器结构完全不同
Mixins 是“复制粘贴”式展开,每次调用都原样生成一套样式规则;Extend 则是“合并选择器”,把调用方的选择器追加到被继承类的选择器列表末尾。
比如 .btn-primary 定义了 color: #fff; background: #007bff;:
-
.submit { .btn-primary(); }→ 输出两行独立规则:.submit { color: #fff; background: #007bff; } -
.submit:extend(.btn-primary);→ 输出一行联合规则:.btn-primary, .submit { color: #fff; background: #007bff; }
后者明显减少重复声明,尤其在多个组件共用同一基础样式时,CSS 文件体积差异会指数级放大。
Extend 不支持伪类和动态参数,Mixins 可以
这是最常踩坑的地方:你不能写 .item:hover:extend(.base:hover),Less 编译会报错 Extend syntax is not allowed in pseudo-classes。同理,:extend() 里不能带变量、计算或条件逻辑。
Mixins 就没这限制:
-
.rounded(@r: 4px) { border-radius: @r; }可传参、可嵌套、可配合if()做条件分支 -
.btn(@bg, @color) { background: @bg; color: @color; }能复用在不同语义场景
所以当你需要“根据状态/尺寸/主题生成不同样式”,只能选 Mixins;而 Extend 只适合“静态样式归并”。
@import (reference) + Extend 是真正按需提取的组合技
很多人以为 @import "utils" 就能直接用里面定义的 class,结果发现最终 CSS 里多了一堆没用的规则——那是没加 (reference)。
正确姿势是:
-
@import (reference) "bootstrap.less";—— 只让 mixins 和 class 可见,不输出任何 CSS -
.my-btn:extend(.btn, .btn-primary);—— 只把真正用到的那几个选择器拉进来
这样编译后,CSS 里只会出现 .btn, .btn-primary, .my-btn { ... } 这一条规则,而不是整个 Bootstrap 的 .btn 相关所有变体。Mixins 做不到这点:哪怕你只调用 .button-variant() 一次,它内部用到的所有颜色计算、hover/focus 状态都会被完整展开。
Extend 的匹配是严格字符串查找,不是作用域解析
Less 不会像 JS 那样做作用域链查找,:extend(.foo) 要求 .foo 必须在当前文件或 @import (reference) 引入的文件中**显式定义过**,且定义位置必须早于 extend 调用(否则报 Unknown error occurred)。
常见翻车点:
- 写了
.wrapper .foo { ... },却在别处.bar:extend(.foo)—— 找不到,因为选择器必须完全一致 - 用了嵌套写法
.nav { &.active { ... } },然后想.menu-item:extend(.nav.active)—— 不行,.nav.active并未作为独立选择器存在 - 在
@import之前就写:extend()—— 编译器还没见过那个 class,直接失败
Mixins 没这问题:只要定义过,随时可调,顺序无关,还能跨文件(只要 import 过)。但代价是,你永远不知道某个 mixin 最终会在多少地方被展开。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











