混合与包含 @mixin and @include

Mixin 允许您定义可在整个样式表中重复使用的样式。 它们可以很容易地避免使用 .float-left 等非语义类,并在库中分发样式集合。

Mixin 是使用 @mixin at-rule 定义的,写为 @mixin <name> { ... }@mixin name(<arguments...>) { ... }。 mixin 的名称可以是任何 Sass 标识符,它可以包含除 top-level statements。 它们可用于封装可放入单个 样式规则 中的样式; 它们可以包含自己的样式规则,这些规则可以嵌套在其他规则中或包含在样式表的顶层; 或者它们只能用于修改变量。

Mixins 使用 @include at-rule 包含在当前上下文中,该规则写为 @include <name>@include <name>(<arguments...>) ,其中包含 mixin 的名称 被包括在内。

scss
Scss
scss
@mixin reset-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

@mixin horizontal-list {
  @include reset-list;

  li {
    display: inline-block;
    margin: {
      left: -2px;
      right: 2em;
    }
  }
}

nav ul {
  @include horizontal-list;
}

💡 有趣的事实:

Mixin 名称,像所有 Sass 标识符一样,将连字符和下划线视为相同。 这意味着 reset-listreset_list 都指的是同一个 mixin。 这是 Sass 早期的历史遗留问题,当时它_只_允许在标识符名称中使用下划线。 一旦 Sass 添加了对连字符的支持以匹配 CSS 的语法,这两者就变得等效,从而使迁移更容易。

参数

Mixins 也可以接受参数,这允许在每次调用它们时自定义它们的行为。 参数在 mixin 名称后的@mixin规则中指定为用括号括起来的变量名称列表。 然后,mixin 必须以 SassScript 表达式 的形式包含相同数量的参数。 这些表达式的值在 mixin 的主体中作为相应的变量可用。

scss
Scss
scss
@mixin rtl($property, $ltr-value, $rtl-value) {
  #{$property}: $ltr-value;

  [dir=rtl] & {
    #{$property}: $rtl-value;
  }
}

.sidebar {
  @include rtl(float, left, right);
}

💡 有趣的事实:

参数列表也可以有尾随逗号! 这使得在重构样式表时更容易避免语法错误。

可选参数

通常,mixin 声明的每个参数都必须在包含该 mixin 时传递。 但是,您可以通过定义一个_默认值_来使参数可选,如果未传递该参数,则将使用该默认值。 默认值使用与 变量声明 相同的语法:变量名称,后跟一个冒号和一个 SassScript 表达式。 这使得定义可以简单或复杂方式使用的灵活混合 API 变得容易。

scss
Scss
scss
@mixin replace-text($image, $x: 50%, $y: 50%) {
  text-indent: -99999em;
  overflow: hidden;
  text-align: left;

  background: {
    image: $image;
    repeat: no-repeat;
    position: $x $y;
  }
}

.mail-icon {
  @include replace-text(url("/images/mail.svg"), 0);
}

💡 有趣的事实:

默认值可以是任何 SassScript 表达式,它们甚至可以引用更早的参数!

关键字参数

包含混入后,除了按参数列表中的位置传递参数外,还可以按名称传递参数。 这对于具有多个可选参数或具有 boolean 参数的 mixins 特别有用,这些参数的含义在没有名称的情况下并不明显。 关键字参数使用与变量声明可选参数 相同的语法。

scss
Scss
scss

⚠️ 注意!

因为 any 参数可以通过名称传递,所以在重命名 mixin 的参数时要小心……它可能会破坏你的用户! 将旧名称作为 optional argument 保留一段时间并打印 [warning](/at-rules /warn) 如果有人通过它,那么他们就知道要迁移到新参数。

任意参数

有时 mixin 能够接受任意数量的参数是很有用的。 如果 @mixin 声明中的最后一个参数以 ... 结尾,则该 mixin 的所有额外参数都将作为 list 传递给该参数。 此参数称为 参数列表

scss
Scss
scss
@mixin order($height, $selectors...) {
  @for $i from 0 to length($selectors) {
    #{nth($selectors, $i + 1)} {
      position: absolute;
      height: $height;
      margin-top: $i * $height;
    }
  }
}

@include order(150px, "input.name", "input.address", "input.zip");

Taking Arbitrary Keyword Arguments

Argument lists can also be used to take arbitrary keyword arguments. The meta.keywords() function takes an argument list and returns any extra keywords that were passed to the mixin as a map from argument names (not including $) to those arguments’ values.

scss
Scss
scss

💡 有趣的事实:

如果您从未将参数列表传递给 meta.keywords() 函数,该参数列表将不允许额外的关键字参数。 这有助于你的 mixin 的调用者确保他们没有不小心拼错任何参数名称。

传递任意参数

就像参数列表允许 mixins 接受任意位置参数或关键字参数一样,相同的语法可用于将位置参数和关键字参数传递给 mixin。 如果您传递一个后跟 ... 的列表作为包含的最后一个参数,则其元素将被视为额外的位置参数。 同样,后跟 ... 的映射将被视为额外的关键字参数。 您甚至可以同时通过两项!

scss
Scss
scss
@use "sass:meta";

@mixin syntax-colors($args...) {
  @debug meta.keywords($args);
  // (string: #080, comment: #800, variable: #60b)

  @each $name, $color in meta.keywords($args) {
    pre span.stx-#{$name} {
      color: $color;
    }
  }
}

@include syntax-colors(
  $string: #080,
  $comment: #800,
  $variable: #60b,
)

💡 有趣的事实:

因为 argument list 跟踪位置参数和关键字参数,所以您可以使用它同时将两者传递给另一个 mixin。 这使得为混入定义别名变得非常容易!

scss
Scss
scss
@mixin btn($args...) {
  @warn "The btn() mixin is deprecated. Include button() instead.";
  @include button($args...);
}

内容块

除了接受参数之外,mixin 还可以接受整个样式块,称为_内容块_。 mixin 可以通过在其主体中包含 @content 规则来声明它采用内容块。 内容块像 Sass 中的任何其他块一样使用大括号传入,并且它被注入以代替 @content 规则。

scss
Scss
scss
@mixin hover {
  &:not([disabled]):hover {
    @content;
  }
}

.button {
  border: 1px solid black;
  @include hover {
    border-width: 2px;
  }
}

💡 有趣的事实:

一个 mixin 可以包含多个 @content 规则。 如果是这样,内容块将分别包含在每个 @content 中。

⚠️ 注意!

内容块是_lexically scoped_,这意味着它只能在包含 mixin 的范围内看到 local variables。 它看不到任何在它传递给的 mixin 中定义的变量,即使它们是在调用内容块之前定义的。

将参数传递给内容块

兼容性: Dart Sass since 1.15.0 | LibSass ✗ | Ruby Sass ✗

mixin 可以将参数传递给它的内容块,就像通过编写@content(<arguments...>)将参数传递给另一个 mixin 一样。 编写内容块的用户可以通过编写@include <name> using (<arguments...>)来接受参数。 内容块的参数列表就像 mixin 的参数列表一样工作,并且通过@content传递给它的参数就像将参数传递给 mixin 一样。

⚠️ 注意!

如果 mixin 将参数传递给它的内容块,则该内容块_必须_声明它接受这些参数。 这意味着只按位置(而不是按名称)传递参数是个好主意,这意味着传递更多参数是一项重大更改。

如果您想灵活地传递给内容块的信息,请考虑向其传递一个 map,其中包含它可能需要的信息!

scss
Scss
scss
@mixin media($types...) {
  @each $type in $types {
    @media #{$type} {
      @content($type);
    }
  }
}

@include media(screen, print) using ($type) {
  h1 {
    font-size: 40px;
    @if $type == print {
      font-family: Calluna;
    }
  }
}

缩进混合语法

缩进语法 除了标准的@mixin@include之外,还有一个用于定义和使用 mixins 的特殊语法。 Mixins 使用字符=定义,并使用+包含它们。 虽然这种语法更简洁,但也更难一目了然,建议用户避免使用它。

sass
Sass
sass
=reset-list
  margin: 0
  padding: 0
  list-style: none

=horizontal-list
  +reset-list

  li
    display: inline-block
    margin:
      left: -2px
      right: 2em

nav ul
  +horizontal-list