LESS - Mixins(混入)

混入 Mixins

混入是指把已存在的样式混入到别的样式中。

你可以把 class 选择器 和 id 选择器混入到其他样式中。例如:
.a, #b {
   color: red;
}

.mixin-class {
  .a();
}
.mixin-id {
  #b();
}

输出结果:

.a, #b {
  color: red;
}
.mixin-class {
  color: red;
}
.mixin-id {
  color: red;
}

注意:当调用 mixin 时,括号是可选的

// 下面两种 mixin 的调用方法效果是一样的
.a, #b {
  color: red;
}

.mixin-class {
  .a();
}
.mixin-class {
  .a;
}
不把 Mixin 输出到编译后的 CSS 中

如果你想用 mixin 但又不想把它输出到编译结果中,在定义 mixin 的时候,在 mixin 后面加上括号

.my-mixin {
  color: black;
}
// 注意 my-other-mixin 后面加了括号
.my-other-mixin() {
  background: white;
}

.class {
  .my-mixin;
  .my-other-mixin;
}

编译输出结果:

.my-mixin {
  color: black;
}
//可以看到这一行并没有输出上面定义的 my-other-mixin. 但是下面的 .class 中却含有 background: white;
.class {
  color: black;
  background: white;
}
Mixin 中使用选择器

Mixin 中不只可以写 css 样式属性,还可以包含选择器。例如:

.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;
}

> 和空格都可以省略。如下

// 下面的写法效果是一样的
#outer > .inner;
#outer > .inner();
#outer .inner;
#outer .inner();
#outer.inner;
#outer.inner();

这种方法的一个用途被称为命名空间。您可以将mixin放在id选择器下,这样可以确保它不会与另一个库冲突(即隔离外界干扰,避免其他样式对该 mixin 的影响)。例如:

#my-library {
  .my-mixin {
    color: black;
  }
}

// 可以如下方法调用
.class {
  #my-library > .my-mixin();
}
命名空间守卫

如果命名空间具有保护,则仅当保护条件返回true时才使用由其定义的mixin。命名空间保护的计算方式与mixin上的保护完全相同,因此接下来两个mixin的工作方式相同:

#namespace when (@mode=huge) {
  .mixin() {/* */}
}

#namespace {
  .mixin() when (@mode=huge) {/* */}
}

下面的 default 函数对于嵌套的 命名空间 和 mixin 有相同的返回值,因此如下的 mixin 永远不会执行。因为它的某一个守卫(即 default()not(default()))肯定是false:

#sp_1 when (default()) {
  #sp_2 when (default()) {
    .mixin() when not(default()) {/* */}
  }
}
!important关键字

在 mixin 调用之后使用 !important 关键字,会把 mixin 所包含的全部css属性标记为 !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 也可以携带参数,这些参数是在选择器调用 mixin 时传递给它的变量.
例如:

.border-radius(@radius) {
  -webkit-border-radius: @radius;
     -moz-border-radius: @radius;
          border-radius: @radius;
}

下面是我们如何调用该mixin:

#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;
}

这样 idheader 的元素会有5px的边框圆角。

也可以不给 mixin 传递参数。当你想在编译后的 CSS 中包含该 mixin 的所有属性, 却又想隐藏某些规则集(ruleset),这会非常有用。

.wrap() {
  text-wrap: wrap;
  white-space: -moz-pre-wrap;
  white-space: pre-wrap;
  word-wrap: break-word;
}

pre { .wrap }

编译后的输出结果为:

// 定义的 .wrap() 这个 mixin, 因为 .wrap 后面加了括号,这个mixin 并没有输出到css中
pre {
  text-wrap: wrap;
  white-space: -moz-pre-wrap;
  white-space: pre-wrap;
  word-break: break-word;
}
携带多个参数的 mixin

多个参数之间用 逗号分号 隔开,推荐用 分号. 逗号有两重意思,它可以被解释为 mixin参数的分隔符 或者是 CSS列表分隔符

使用逗号作为 mixin 参数分隔符时,而 mixin 的每一个参数又是需要用逗号分开的列表,这将不可能实现。另一方面,如果编译器在调用或声明 mixin 的地方发现至少一个 分号 ,编译器就会认为所有的参数将以 分号 分隔,所有的逗号都是css列表:

  • 两个参数,每个参数是逗号分隔的列表: .name(1, 2, 3; something, else).
  • 三个参数,每个参数都是一个数字: .name(1, 2, 3).
  • 使用伪分号创建一个包含逗号分隔css列表的参数的mixin调用: .name(1, 2, 3;).
  • 逗号分隔默认值: .name(@param1: red, blue;).

使用相同的名称和参数数量定义多个 mixins 是允许的。LESS 会使用所有 可以使用的 css属性。记住如下mixin编译规则:
如果以 .mixin(green) 这样只携带一个参数的方式使用这多个相同名称的 mixin,则所有相同名称的 mixins 且参数列表中只含有该必填参数,其他参数都为可选的 mixins 中所包含的全部 css 样式合并起来,赋予给调用这个只传了一个必传参数的mixin的选择器

// 定义第 1 个 .mixin 混入函数
.mixin(@color) { // 这里的 color 参数在调用 .mixin 时是必传的,因为没有给 color 设置默认颜色值
  color-1: @color;
}

// 定义第 2 个 .mixin 混入函数,它和上一个混入函数同名
.mix(@color; @padding: 2) { // 这里的 color 也是必传的。padding参数是选填的,因为有默认值
  color-2: @color;
  padding-2: @padding;
}

// 定义第 3 个 .mixin 混入函数,它和第1、2个混入函数同名
.mixin(@color; @padding; @margin: 2) { // 这里的 color 是必传的,需要注意的是,padding也是必传的,
                                       // 和1、2两个 mixin 不同的是,这个 mixin 有2个必传参数,
                                       // margin 参数可以省略,因为有默认值
  color-3: @color;
  padding-3: @padding;
  margin: @margin @margin @margin @margin;
}


.some .selector div {
  .mixin(#008000); // 这里只传入了 color 这一个必填参数。注意看下面编译的结果
}

最终编译输出的结果为:

.some .selector div {
  color-1: #008000;
  color-2: #008000;
  padding-2: 2;
}

上面的编译结果,是因为在调用同名的 mixin 函数 .mixin 时,只传入了一个参数 color,我们逐步看一下最终的编译结果是怎么出来的。

  1. 在第一个 .mixin 中,参数 @color 是必传的,根据上面的mixin编译规则,该 mixin 中包含的 css 样式最终会编译进调用它的选择器中。
  2. 在第二个 .mixin 中,参数 @color 是必传的,@padding 是可省略的,因此该 mixin 中只有 @color 一个必传参数,根据mixin编译规则,该 mixin 中包含的 css 样式最终也会编译进调用它的选择器中。
  3. 在第三个 .mixin 中,参数 @color @padding 都是必传的,根据mixin编译规则,不符合只有 @color 这一个必传参数的原则,因此该 mixin 中的所有样式 都不会 编译进输出结果中。
命名参数

mixin 不只可以通过参数位置来传递实参,可以通过参数名称来给它传递实参。任何的 mixin 形参都可以通过指定形参名称来给它传递实参,而不依赖于定义该 mixin 时的形参顺序:

.mixin(@color: black; @margin: 10px; @padding: 20px) {
  color: @color;
  margin: @margin;
  padding: @padding;
}


.class1 {
  .mixin(@margin: 20px; @color: #33acfe); // 调用 mixin 时通过指定形参名称传递实参值,并没有按照定义 
                                          // mixin 时的顺序 先 color  其次 margin 最后 padding 的
                                          // 顺序来传值
}
.class2 {
  .mixin(#efca44; @padding: 40px); // 按原有的形参顺序传值时,可以不指定形参名
}
@arguments变量

@arguments 在 mixins 中有独特的含义,它包含了传入的所有参数,当该 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 个 arguments
.mixin() {    // 匹配第 0 个 arguments
.mixin(@a: 1) { // 匹配第 0 -1 个 arguments
.mixin(@a: 1; ...) { // 匹配 0 - N 个 arguments
.mixin(@a; ...) { // 匹配 1 - N 个 arguments

此外:

.mixin(@a; @rest...) {
  // @rest 绑定到 @a 之后的所有参数
  // @arguments 绑定到所有参数
}
模式匹配

有时候我们想根据传入的参数改变一个 mixin 的行为。让我们从一个基础的例子开始:

.mixin(@s; @color) {...}

.class {
  .mixin(@switch; #888);
}

我们想根据 @switch 的不同让 mixin 表现出不同的结果。我们可以如下定义 .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 传入 color 的地方会变亮。如果 @switch 的值为 dark, 结果就是一个比较暗的颜色。我们逐步分析是怎么编译出来的:

  • 第一个 mixin 不匹配,因为第一个参数为 dark
  • 第二个 mixin 匹配,因为它的第一个参数为 light
  • 第三个 mixin 匹配,因为它的第一个参数接受任意值
    只有匹配的 mixin 才会被采用。变量匹配并绑定到任意值。变量以外的任何内容都只和等于自身的值匹配。
    我们也可以匹配参数个数,看下面的例子:
.mixin(@a) {
  color: @a;
}
.mixin(@a; @b) {
  color: fade(@a; @b);
}

如果我们调用 .mixin 时只传入了一个参数, 我们会得到第一个 .mixin 的编译结果.如果传入了两个参数,就会得到第二个 .mixin 的编译结果,即 @a 变为 @b.

作为函数的 mixins

从 mixins 中返回变量或 mixins
在 mixin 中定义的变量和 mixin 是可见的,可以在调用者的作用域中使用。只有一个例外,如果调用方包含同名变量(包括由另一个 mixin 调用定义的变量),则不复制变量。只有调用方本地作用域中存在的变量才受保护。从父作用域继承的变量将被重写(覆盖)。
例如:

.mixin() {
  @width: 100%;
  @height: 200px;
}

.caller {
  .mixin();
  width: @width;
  height: @height;
}

编译结果为:

.caller {
  width: 100%;
  height: 200px;
}

因此,mixin中定义的变量可以作为其返回值。这允许我们创建一个可以像函数一样使用的mixin
例如:

.average(@x, @y) {
  @average: ((@x + @y) / 2);
}
div {
  .average(16px, 50px); // 调用 mixin
  padding: @average;
}

编译结果为:

div {
  padding: 33px;
}

在调用者作用域内定义的变量不会被覆盖。然而,在调用者父级作用域中定义的变量将不被保护且可以被覆盖:

.mixin() {
  @size: in-mixin;
  @defineOnlyInMixin: in-mixin;
}

.class {
  margin: @size @defineOnlyInMixin;
  .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 被拷贝到这里且可用
}

编译结果

#namespace {
  declaration: 5;
}

你可能感兴趣的:(LESS - Mixins(混入))