Mixins
从现有样式中“混合”属性
你可以混合类选择器和 ID 选择器,例如:
.a,
#b {
color: red;
}
.mixin-class {
.a();
}
.mixin-id {
#b();
}
结果为:
.a,
#b {
color: red;
}
.mixin-class {
color: red;
}
.mixin-id {
color: red;
}
在以前的版本中,mixins 调用中的括号是可选的,但是可选的括号已被弃用,并且将在未来的版本中需要。
.a();
.a; //目前可以使用,但已弃用;不要使用
.a (); //括号前的空格也已弃用
带括号的 mixins
如果要创建 mixins,但不希望该 mixins 出现在 CSS 输出中,请在 mixins 定义后加上括号。
.my-mixins {
color: black;
}
.my-other-mixin() {
background: white;
}
.class {
.my-mixin();
.my-other-mixin();
}
输出
.my-mixins {
color: black;
}
.class {
color: black;
background: white;
}
mixins 中的选择器
mixins 可以包含更多内容,而不仅仅是属性,它们还可以包含选择器。
例如:
.my-hover-mixin() {
&:hover {
border: 1px solid red;
}
}
button {
.my-hover-mixin();
}
输出
button:hover {
border: 1px solid red;
}
命名空间
如果要在更复杂的选择器中混合属性,则可以堆叠多个 ID 或类。
#outer() {
.inner {
color: red;
}
}
.c {
#outer.inner();
}
注意:传统的 Less 语法允许在命名空间和 mixins 之间使用“>”和空格。此语法已弃用并可能被删除。目前,这些做相同的事情。
#outer > .inner(); //已弃用
#outer .inner(); //已弃用
#outer.inner(); //首选
像这样对 mixins 进行命名空间设置可以减少与其它库 mixins 或用户 mixins 的冲突,但也可以是“组织”mixins 组的一种方式。
例:
#my-library {
.my-mixin() {
color: black;
}
}
//可以像这样使用
.class {
#my-library.my-mixin();
}
受保护的命名空间
如果命名空间具有保护条件,则仅在保护条件返回 true 时使用由其定义的 mixin。命名空间保护条件的评估方式与 mixins 上的保护条件完全相同,因此以下两个 mixins 的工作方式相同:
#namespace when (@mode = huge) {
.mixin() {
/* */
}
}
#namespace {
.mixin() when (@mode = huge) {
/* */
}
}
假定“default”函数对所有嵌套命名空间和 mixins 具有相同的值。
以下 mixins 永远不会被评估;其中一个保护条件保证为 false:
#sp_1 when (default()) {
#sp_2 when (default()) {
.mixin() when not(default()) {
/* */
}
}
}
!important 关键字
在 mixins 调用后使用 !important
关键字,将其继承的所有属性标记为 !important
:
示例:
.foo (@bg: #f5f5f5, @color: #900) {
background: @bg;
color: @color;
}
.unimportant {
.foo();
}
.important {
.foo() !important;
}
结果为:
.unimportant {
background: #f5f5f5;
color: #900;
}
.important {
background: #f5f5f5 !important;
color: #900 !important;
}
Parametric Mixins
如何向 mixins 传递参数
mixins 也可以接受参数,这些参数是在混合到选择器块时传递的变量。
例如:
.border-radius(@radius) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
border-radius: @radius;
}
以下是如何将其混合到各种规则集中的方法:
#header {
.border-radius(4px);
}
.button {
.border-radius(6px);
}
参数化 mixins 也可以为其参数设置默认值:
.border-radius(@radius: 5px) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
border-radius: @radius;
}
现在我们可以这样调用它:
#header {
.border-radius();
}
它将包括一个 5px 的边框半径。
你还可以使用不带参数的参数化 mixin。如果你想要隐藏规则集并将其属性包含在其它规则集中,则此功能非常有用:
.wrap() {
text-wrap: wrap;
white-space: -moz-pre-wrap;
white-space: pre-wrap;
word-wrap: break-word;
}
pre {
.wrap();
}
它将输出:
pre {
text-wrap: wrap;
white-space: -moz-pre-wrap;
white-space: pre-wrap;
word-wrap: break-word;
}
参数分隔符
参数目前可以使用分号或逗号分隔。
最初,参数只由逗号分隔,但后来添加了分号以支持将逗号分隔的列表值传递给单个参数。
注意:从 Less 4.0 开始,你可以使用括号转义 [~()
] 包装列表值,例如 .name(@param1: ~(red, blue))
。这类似于引号转义语法:~"quote"
。这可能会使你的代码库中的分号分隔符不必要。
示例:
- 两个参数,每个参数都包含逗号分隔的列表:
.name(1, 2, 3; something, else)
- 三个参数,每个参数都包含一个数字:
.name(1, 2, 3)
- 使用虚拟分号创建一个带有包含逗号分隔的 CSS 列表的参数的 mixins 调用:
.name(1, 2, 3;)
。注意:如果尾随分号看起来奇怪,你可能更喜欢:.name(~(1, 2, 3))
- 编写逗号分隔的默认值的方法:
@param-values: red, blue; .name(@param1: @param-values)
..name(@param1: red, blue;)
.name(@param1: ~(red, blue))
重载 mixins
定义具有相同名称和参数数量的多个 mixins 是合法的。Less 将使用所有可应用的属性。如果你使用了一个参数的 mixin,例如 .mixin(green);
,则属性将应用于所有具有一个参数的 mixin。
具有一个必选参数的所有 mixins 的属性将被使用:
.mixin(@color) {
color-1: @color;
}
.mixin(@color, @padding: 2) {
color-2: @color;
padding-2: @padding;
}
.mixin(@color, @padding, @margin: 2) {
color-3: @color;
padding-3: @padding;
margin: @margin @margin @margin @margin;
}
.some .selector div {
.mixin(#008000);
}
编译为:
.some .selector div {
color-1: #008000;
color-2: #008000;
padding-2: 2;
}
命名参数
mixins 引用可以通过它们的名称而不是位置提供参数值。任何参数都可以通过它的名称引用,它们不必按任何特定顺序:
.mixin(@color: black; @margin: 10px; @padding: 20px) {
color: @color;
margin: @margin;
padding: @padding;
}
.class1 {
.mixin(@margin: 20px; @color: #33acfe);
}
.class2 {
.mixin(#efca44; @padding: 40px);
}
编译为:
.class1 {
color: #33acfe;
margin: 20px;
padding: 20px;
}
.class2 {
color: #efca44;
margin: 10px;
padding: 40px;
}
@arguments 变量
@arguments
在 mixins 内部具有特殊含义,它包含调用 mixins 时传递的所有参数。如果你不想处理单个参数,则这很有用:
.box-shadow(@x: 0, @y: 0, @blur: 1px, @color: #000) {
-webkit-box-shadow: @arguments;
-moz-box-shadow: @arguments;
box-shadow: @arguments;
}
.big-block {
.box-shadow(2px, 5px);
}
结果为:
.big-block {
-webkit-box-shadow: 2px 5px 1px #000;
-moz-box-shadow: 2px 5px 1px #000;
box-shadow: 2px 5px 1px #000;
}
高级参数和@rest变量
如果你希望 mixins 接受可变数量的参数,则可以使用...
。在变量名称后使用此选项将这些参数分配给变量。
.mixin(...) { // 匹配0-N个参数
.mixin() { // 匹配恰好0个参数
.mixin(@a: 1) { // 匹配0-1个参数
.mixin(@a: 1, ...) { // 匹配0-N个参数
.mixin(@a, ...) { // 匹配1-N个参数
此外:
.mixin(@a, @rest...) {
// @rest绑定到@a之后的参数
// @arguments绑定到所有参数
}
模式匹配
有时,你可能希望根据传递给它的参数更改 mixins 的行为。让我们从基础知识开始:
.mixin(@s, @color) {
...;
}
.class {
.mixin(@switch, #888);
}
现在假设我们希望.mixin
根据传递给它的参数更改行为。
根据 @switch
的值不同,我们可以定义 .mixin
如下:
.mixin(dark, @color) {
color: darken(@color, 10%);
}
.mixin(light, @color) {
color: lighten(@color, 10%);
}
.mixin(@_, @color) {
display: block;
}
现在,如果我们运行:
@switch: light;
.class {
.mixin(@switch, #888);
}
我们将得到以下 CSS:
.class {
color: #a2a2a2;
display: block;
}
其中传递给 .mixin
的颜色被变亮了。如果 @switch
的值是 dark
,结果将是一个更暗的颜色。
这里发生了什么:
- 第一个 mixins 定义没有匹配,因为它期望第一个参数是
dark
。 - 第二个 mixins 定义匹配,因为它期望
light
。 - 第三个 mixins 定义匹配,因为它期望任何值。
只有匹配的 mixins 定义被使用。变量匹配并绑定到任何值。除了变量之外的任何内容都只与等于自身的值匹配。
我们还可以根据参数数量进行匹配,这是一个例子:
.mixin(@a) {
color: @a;
}
.mixin(@a, @b) {
color: fade(@a, @b);
}
现在,如果我们使用一个参数调用 .mixin
,我们将得到第一个定义的输出,但如果我们使用 两个 参数调用它,我们将得到第二个定义,即将 @a
淡化为 @b
。
Using Mixins as Funtions
从 mixins 调用中选择属性和变量
属性/值访问器
发布于 v3.5.0
从 Less 3.5 开始,你可以使用属性/变量访问器从已评估的 mixins 规则中选择值。这可以让你像使用函数一样使用 mixin。
例如:
.average(@x, @y) {
@result: ((@x + @y) / 2);
}
div {
// 调用 mixins并查找其 "@result" 值
padding: .average(16px, 50px) [ @result];
}
结果为:
div {
padding: 33px;
}
覆盖 mixins 值
如果有多个匹配的 mixin,则会评估并合并所有规则,并返回具有该标识符的最后一个匹配值。这类似于 CSS 中的级联,它允许你“覆盖”mixins 值。
// library.less
#library() {
.mixin() {
prop: foo;
}
}
// customize.less
@import "library";
#library() {
.mixin() {
prop: bar;
}
}
.box {
my-value: #library.mixin[prop];
}
输出:
.box {
my-value: bar;
}
未命名查找
如果在 mixins 或 ruleset 调用之后不在 [@lookup]
中指定查找值,而是在 mixins 或 ruleset 调用后写 []
,则 所有 值都会级联,选择最后声明的值。
意思是:上面示例中的平均值 mixins 可以写成:
.average(@x, @y) {
@result: ((@x + @y) / 2);
}
div {
// 调用 mixins并查找其最终值
padding: .average(16px, 50px) [];
}
输出相同:
div {
padding: 33px;
}
对于别名为 mixins 调用的 ruleset 或变量,相同的级联行为也是正确的。
@dr: {
value: foo;
};
.box {
my-value: @dr[];
}
这将输出:
.box {
my-value: foo;
}
将 mixins 和变量解锁到调用者范围
已弃用 - 使用属性/值访问器
在 mixins 中定义的变量和 mixins 可见,并且可以在调用者的范围内使用。只有一个例外:如果调用者包含具有相同名称的变量(包括由另一个 mixins 调用定义的变量),则不会复制变量。只有出现在调用者本地范围中的变量受到保护。从父范围继承的变量将被覆盖。
注意:此行为已弃用,将来,变量和 mixins 将不会以这种方式合并到调用者范围中。
例如:
.mixin() {
@width: 100%;
@height: 200px;
}
.caller {
.mixin();
width: @width;
height: @height;
}
结果为:
.caller {
width: 100%;
height: 200px;
}
直接在调用者范围内定义的变量无法被覆盖。但是,在调用者父范围中定义的变量没有受到保护,将被覆盖:
.mixin() {
@size: in-mixin;
@definedOnlyInMixin: in-mixin;
}
.class {
margin: @size @definedOnlyInMixin;
.mixin();
}
@size: globaly-defined-value; // 调用者父范围 - 没有保护
结果为:
.class {
margin: in-mixinsin-mixin;
}
最后,mixins 在 mixins 中定义也作为返回值:
.unlock(@value) {
// 外部mixin
.doSomething() {
// 嵌套mixin
declaration: @value;
}
}
#namespace {
.unlock(5); // 解锁doSomething mixin
.doSomething(); //嵌套mixin被复制到此处并可用
}
结果为:
#namespace {
declaration: 5;
}
递归
创建循环
在 Less 中,mixins 可以调用自身。这种递归 mixins 结合 Guard Expressions 和 Pattern Matching 可以用于创建各种迭代/循环结构。
例如:
.loop(@counter) when (@counter > 0) {
.loop((@counter - 1)); // 下一次迭代
width: (10px * @counter); // 每次迭代的代码
}
div {
.loop(5); // 启动循环
}
输出:
div {
width: 10px;
width: 20px;
width: 30px;
width: 40px;
width: 50px;
}
使用递归循环生成 CSS 网格类的通用示例:
.generate-columns(4);
.generate-columns(@n, @i: 1) when (@i =< @n) {
.column-@{i} {
width: (@i * 100% / @n);
}
.generate-columns(@n, (@i + 1));
}
输出:
.column-1 {
width: 25%;
}
.column-2 {
width: 50%;
}
.column-3 {
width: 75%;
}
.column-4 {
width: 100%;
}
Mixin Guards
当你想匹配表达式而不是简单值或元数时,守卫很有用。如果你熟悉函数式编程,你可能已经遇到过它们。
为了尽可能接近 CSS 的声明性质,Less 选择通过守卫混合来实现条件执行,而不是 if
/else
语句,类似于 @media
查询特性规范。
让我们从一个例子开始:
.mixin(@a) when (lightness(@a) >= 50%) {
background-color: black;
}
.mixin(@a) when (lightness(@a) < 50%) {
background-color: white;
}
.mixin(@a) {
color: @a;
}
关键是 when
关键字,它引入了一个守卫序列(这里只有一个守卫)。现在如果我们运行以下代码:
.class1 {
.mixin(#ddd);
}
.class2 {
.mixin(#555);
}
我们将得到以下结果:
.class1 {
background-color: black;
color: #ddd;
}
.class2 {
background-color: white;
color: #555;
}
守卫比较运算符
可用于守卫的完整比较运算符列表为:>
, >=
, =
, =<
, <
。此外,关键字 true
是唯一的真值,使得这两个混合物等价:
.truth(@a) when (@a) {
...;
}
.truth(@a) when (@a = true) {
...;
}
除了关键字 true
之外的任何值都是假值:
.class {
.truth(40); // 不会匹配上面的任何定义。
}
请注意,你还可以将参数与其它参数或非参数进行比较:
@media: mobile;
.mixin(@a) when (@media = mobile) {
...;
}
.mixin(@a) when (@media = desktop) {
...;
}
.max(@a; @b) when (@a > @b) {
width: @a;
}
.max(@a; @b) when (@a < @b) {
width: @b;
}
守卫逻辑运算符
你可以在守卫中使用逻辑运算符。语法基于 CSS 媒体查询。
使用 and
关键字组合守卫:
.mixin(@a) when (isnumber(@a)) and (@a > 0) {
...;
}
你可以通过用逗号 ,
分隔守卫来模拟 or 运算符。如果任何一个守卫计算为 true,则被视为匹配:
.mixin(@a) when (@a > 10), (@a < -10) {
...;
}
使用 not
关键字来否定条件:
.mixin(@b) when not (@b > 0) {
...;
}
类型检查函数
最后,如果你想根据值类型匹配混合物,可以使用 is
函数:
.mixin(@a; @b: 0) when (isnumber(@b)) {
...;
}
.mixin(@a; @b: black) when (iscolor(@b)) {
...;
}
以下是基本的类型检查函数:
函数:
iscolor
:判断是否为颜色值isnumber
:判断是否为数字isstring
:判断是否为字符串iskeyword
:判断是否为关键字isurl
:判断是否为 URL
如果你想要检查一个值是否为特定单位的数字,你可以使用以下其中之一:
ispixel
:判断是否为像素值ispercentage
:判断是否为百分比值isem
:判断是否为 em 值isunit
:判断是否为单位值
Aliasing Mixins
发布 v3.5.0
将 mixins 调用分配给变量
mixins 可以分配给变量,以便作为变量调用,或者可以用于映射查找。
#theme.dark.navbar {
.colors(light) {
primary: purple;
}
.colors(dark) {
primary: black;
secondary: grey;
}
}
.navbar {
@colors: #theme.dark.navbar.colors(dark);
background: @colors[primary];
border: 1px solid @colors[secondary];
}
这将输出:
.navbar {
background: black;
border: 1px solid grey;
}
变量调用
整个 mixins 调用可以被别名,并作为变量调用。例如:
#library() {
.colors() {
background: green;
}
}
.box {
@alias: #library.colors();
@alias();
}
输出:
.box {
background: green;
}
请注意,与在根中使用的 mixins 不同,分配给变量并且 没有参数调用 的 mixins 调用始终需要括号。以下是无效的。
#library() {
.colors() {
background: green;
}
}
.box {
@alias: #library.colors;
@alias(); // 错误:无法评估变量调用 @alias
}
这是因为变量是否分配了选择器列表或 mixins 调用是不明确的。例如,在 Less 3.5+ 中,可以这样使用此变量。
.box {
@alias: #library.colors;
@{alias} {
a: b;
}
}
上述将输出:
.box #library.colors {
a: b;
}