这是http://lesscss.org/features/#mixins-feature部分的翻译。
混合(Mixins)
现有样式的“混合”属性
您可以混合使用类选择器和ID选择器,例如
.a, #b {
color: red;
}
.mixin-class {
.a();
}
.mixin-id {
#b();
}
编译结果是:
.a, #b {
color: red;
}
.mixin-class {
color: red;
}
.mixin-id {
color: red;
}
目前mixin调用中的括号是可选的,但建议严格使用括号,并且在将来的版本中将必须使用括号。
.a();
.a; // 目前可以使用,但已废弃,请不要这样使用
不输出mixin
如果要创建一个mixin,但又不希望该mixin出现在CSS输出中,请在mixin定义后加上括号。
.my-mixin {
color: black;
}
.my-other-mixin() {
background: white;
}
.class {
.my-mixin();
.my-other-mixin();
}
输出
.my-mixin {
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;
}
命名空间
如果要在更复杂的选择器中使用mixins,则可以罗列多个ID或类。
#outer() {
.inner {
color: red;
}
}
.c {
#outer > .inner();
}
这两个>
和空白都是可选
// 都是做一样的事情
#outer > .inner();
#outer .inner();
#outer.inner();
将你的mixins用命名空间包裹可以减少与其他库mixins或用户mixins的冲突,它也可以是“组织”mixins的一种方式。
例:
#my-library {
.my-mixin() {
color: black;
}
}
// 可以这样使用
.class {
#my-library.my-mixin();
}
受保护的命名空间
如果名称空间被保护了,则仅当保护条件返回true时,才使用由其定义的mixins。保护命名空间的方式与保护Mixin的方式是一致的,因此以下两个Mixin的工作方式是等价的:
#namespace when (@mode = huge) {
.mixin() { /* */ }
}
#namespace {
.mixin() when (@mode = huge) { /* */ }
}
default
函数假定所有的嵌套命名空间和mixin具有相同的值。以下mixins永远不会被评估,因为保护mixins的条件为false:
#sp_1 when (default()) {
#sp_2 when (default()) {
.mixin() when not(default()) { /* */ }
}
}
该 !important
关键字
在mixin调用之后使用关键字!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;
}
参数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的边框半径。
您也可以不带参数来使用参数mixins,通常用于您想在CSS输出中隐藏某些规则集,但又想将其属性包含在其他规则集中。
.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;
}
具有多个参数的Mixins
参数以分号或逗号分隔,建议使用分号。逗号具有双重含义:可以将其解释为mixin参数分隔符或css列表分隔符。
使用逗号作为mixin分隔符将不能用逗号分隔的列表作为参数。另一方面,如果编译器在mixin调用或声明中看到至少一个分号,则假定参数用分号分隔,其他所有逗号都属于css列表:
- 两个参数,每一个包含逗号分隔的列表:
.name(1, 2, 3; something, else)
, - 三个参数,并且每个包含一个数字:
.name(1, 2, 3)
, - 使用虚拟分号创建混入调用一个参数包含逗号分隔的CSS列表:
.name(1, 2, 3;)
, - 逗号分隔的默认值:
.name(@param1: red, blue;)
。
不支持使用一个名字但是参数个数不同来区分mixins。less会使用所有能用上属性。如果您使用mixin只提供了一个参数,例如.mixin(green);
,那么将会把所有的参数强行设置成同一个值:
.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;
}
命名参数
mixin不仅仅是可以通过位置,也可以通过名称来提供参数值。可以通过名称来引用任何参数,并且它们可以使用任意顺序:
.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
在mixin内部有特殊含义,它包含调用mixin时传递的所有参数。如果您不想单个处理参数,这将非常有用:
.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
变量
如果您希望mixin接受可变数量的参数,则可以使用...
。在变量名之后直接使用...
会将这些参数分配给变量。
.mixin(...) { // 匹配 0-N 个参数
.mixin() { // 精确匹配 0个参数
.mixin(@a: 1) { // 匹配 0-1 个参数
.mixin(@a: 1; ...) { // 匹配 0-N 个参数
.mixin(@a; ...) { // 匹配1-N arguments
此外:
.mixin(@a; @rest...) {
// @rest 将绑定为 @a后的所有变量
// @arguments 绑定为所有变量
}
模式匹配
有时,您可能想根据传递给它的参数来更改mixin的行为。让我们从一些基本的东西开始:
.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
,其结果将是一个较深的颜色。
这是由于以下原因导致的:
- 第一个mixin定义不匹配,因为它应
dark
作为第一个参数。 - 第二个mixin定义匹配,因为它符合
light
。 - 第三个mixin定义匹配,因为它期望任何值。
只有mixin定义匹配时才会被使用。变量可以匹配并绑定到任意值。除变量外,其他任何事物都仅与等于其自身的值匹配。
我们还可以匹配多个参数,这是一个示例:
.mixin(@a) {
color: @a;
}
.mixin(@a; @b) {
color: fade(@a; @b);
}
现在,如果使用单个参数调用.mixin
,则将获取第一个定义的输出,但是如果使用两个参数调用,则将获取第二个定义,即@a
淡出为@b
。
使用Mixins作为函数
从mixin调用中选择属性和变量
属性/值访问器
v3.5.0引入
从Less 3.5开始,您可以使用属性/值访问器从评估的mixin规则中选择一个值。这可以允许您使用与功能相似的mixin。
例:
.average(@x, @y) {
@result: ((@x + @y) / 2);
}
div {
// call a mixin and look up its "@result" value
padding: .average(16px, 50px)[@result];
}
结果是:
div {
padding: 33px;
}
重写mixin值
如果您有多个匹配的mixin,则将评估并合并所有规则,并返回带有该标识符的最后一个匹配值。这类似于CSS中的层叠,它允许您“重写” mixin值。
// library.less
#library() {
.mixin() {
prop: foo;
}
}
// customize.less
@import "library";
#library() {
.mixin() {
prop: bar;
}
}
.box {
my-value: #library.mixin[prop];
}
输出:
.box {
my-value: bar;
}
未命名的查找
如果您未在其中指定查找值[@lookup]
,而是[]
在mixin或规则集调用之后写入,则所有值将重叠,最后一个声明的值将被选择。
这意味着:上面示例中的平均值mixin可以写成:
.average(@x, @y) {
@result: ((@x + @y) / 2);
}
div {
// 调用mixin并查找它的最终值
padding: .average(16px, 50px)[];
}
输出是相同的:
div {
padding: 33px;
}
mixin调用时会用规则集或变量替换,也会产生重叠行为。
@dr: {
value: foo;
}
.box {
my-value: @dr[];
}
输出:
.box {
my-value: foo;
}
将mixins和变量解锁到调用者作用域中
已过时-使用属性/值访问器
mixin中定义的变量和mixin是可见的,可以在调用者的作用域中使用。只有一个例外:如果调用者包含具有相同名称的变量(其中包括由另一个mixin调用定义的变量),则不会复制变量。只有在调用者本地作用域内的变量受到保护。从父范围继承的变量将被覆盖。
注意:这种用法即将过时,以后变量和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-mixin in-mixin;
}
最后,在mixin中定义的mixin也充当返回值:
.unlock(@value) { // 外层 mixin
.doSomething() { // 嵌套 mixin
declaration: @value;
}
}
#namespace {
.unlock(5); // unlock doSomething mixin
.doSomething(); //nested mixin was copied here and is usable
}
结果是:
#namespace {
declaration: 5;
}
mixin递归
创建循环
在Less中,mixin可以自调用。与守护表达式和模式匹配结合使用时,此类递归mixin 可用于创建各种迭代/循环结构。
例:
.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守护
当您想在表达式上进行匹配时,保护很有用,就如同简单值或参数个数的比较一样。如果您熟悉函数式编程,可能已经遇到过了。
为了尽量与CSS的声明相近,Less选择了通过被守护的mixin而不是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
是唯一的真实值,使这两个mixins等效:
.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) { ... }
您可以通过用逗号分隔s守护来模仿or运算符,
。如果任何一个守护的值为true,则认为是匹配:
.mixin(@a) when (@a > 10), (@a < -10) { ... }
使用not
关键字来进行取反操作:
.mixin(@b) when not (@b > 0) { ... }
类型检查功能
最后,如果您要根据值类型来匹配mixin,则可以使用以下is
功能:
.mixin(@a; @b: 0) when (isnumber(@b)) { ... }
.mixin(@a; @b: black) when (iscolor(@b)) { ... }
以下是基本的类型检查功能:
iscolor
isnumber
isstring
iskeyword
isurl
如果要检查值是否是数字,是否还使用特定单位,则可以使用以下方法之一:
ispixel
ispercentage
isem
isunit
Mixin别名
v3.5.0引入
将mixin调用赋值给变量
可以将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;
}
变量调用
整个mixin调用可以用别名引用并称为变量调用。如:
#library() {
.rules() {
background: green;
}
}
.box {
@alias: #library.rules();
@alias();
}
输出:
.box {
background: green;
}
请注意,与root中使用的mixin不同,分配给变量且不带参数的 mixin调用始终需要括号。以下无效。
#library() {
.rules() {
background: green;
}
}
.box {
@alias: #library.colors; // 错误: 没有使用括号
@alias(); // 错误: 无法使用@alias进行调用
}
这是因为究竟是变量分配选择器列表还是mixin调用是不明确的。例如在Less 3.5+中,可以用这种方式使用此变量。
.box {
@alias: #library.colors;
@{alias} {
a: b;
}
}
以上将输出:
.box #library.colors {
a: b;
}