@mixin 和 @include

Mixin 允许您定义可在整个样式表中重复使用的样式。它们让您轻松避免使用像 .float-left 这样的非语义类,并将样式集合分布在库中。

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

Mixin 使用 @include at-rule 包含到当前上下文中,写法为 @include <name>@include <name>(<arguments...>),其中包含 Mixin 的名称。

游乐场

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;
}
游乐场

Sass 语法

@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

CSS 输出

nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
nav ul li {
  display: inline-block;
  margin-left: -2px;
  margin-right: 2em;
}











💡 有趣的事实

Mixin 名称(与所有 Sass 标识符一样)将连字符和下划线视为相同。这意味着 reset-listreset_list 都指向同一个 Mixin。这是 Sass 最初时期的历史遗留问题,那时它允许在标识符名称中使用下划线。当 Sass 添加了对连字符的支持以匹配 CSS 的语法后,这两个符号被等效以简化迁移。

参数参数永久链接

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

游乐场

SCSS 语法

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

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

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

Sass 语法

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

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



.sidebar
  @include rtl(float, left, right)

CSS 输出

.sidebar {
  float: left;
}
[dir=rtl] .sidebar {
  float: right;
}





💡 有趣的事实

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

可选参数可选参数永久链接

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

游乐场

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);
}
游乐场

Sass 语法

@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)



CSS 输出

.mail-icon {
  text-indent: -99999em;
  overflow: hidden;
  text-align: left;
  background-image: url("/images/mail.svg");
  background-repeat: no-repeat;
  background-position: 0 50%;
}







💡 有趣的事实

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

关键字参数关键字参数永久链接

当包含 Mixin 时,除了按参数列表中的位置传递参数之外,还可以按名称传递参数。这对于具有多个可选参数或具有 布尔值 参数(如果没有名称很难理解其含义)的 Mixin 特别有用。关键字参数使用与 变量声明可选参数 相同的语法。

游乐场

SCSS 语法

@mixin square($size, $radius: 0) {
  width: $size;
  height: $size;

  @if $radius != 0 {
    border-radius: $radius;
  }
}

.avatar {
  @include square(100px, $radius: 4px);
}
游乐场

Sass 语法

@mixin square($size, $radius: 0)
  width: $size
  height: $size

  @if $radius != 0
    border-radius: $radius



.avatar
  @include square(100px, $radius: 4px)

CSS 输出

.avatar {
  width: 100px;
  height: 100px;
  border-radius: 4px;
}







⚠️ 注意!

因为任何参数都可以按名称传递,所以请谨慎重命名 Mixin 的参数……这可能会破坏您的用户!可以将旧名称保留一段时间作为 可选参数,如果有人传递它,则打印一个 警告,这样他们就知道要迁移到新的参数。

接受任意参数接受任意参数永久链接

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

游乐场

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");






游乐场

Sass 语法

@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")






CSS 输出

input.name {
  position: absolute;
  height: 150px;
  margin-top: 0px;
}

input.address {
  position: absolute;
  height: 150px;
  margin-top: 150px;
}

input.zip {
  position: absolute;
  height: 150px;
  margin-top: 300px;
}

接受任意关键字参数接受任意关键字参数永久链接

参数列表也可用于接受任意关键字参数。 meta.keywords() 函数 接受一个参数列表,并将传递给 Mixin 的任何额外关键字作为从参数名称(不包括 $)到这些参数值的 映射 返回。

游乐场

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,
)
游乐场

Sass 语法

@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)




CSS 输出

pre span.stx-string {
  color: #080;
}

pre span.stx-comment {
  color: #800;
}

pre span.stx-variable {
  color: #60b;
}







💡 有趣的事实

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

传递任意参数传递任意参数永久链接

就像参数列表允许 Mixin 接受任意位置或关键字参数一样,可以使用相同的语法来传递位置和关键字参数给 Mixin。如果您将列表后跟 ... 作为包含的最后一个参数,则它的元素将被视为附加的位置参数。类似地,以 ... 结尾的映射将被视为附加的关键字参数。您甚至可以同时传递两者!

游乐场

SCSS 语法

$form-selectors: "input.name", "input.address", "input.zip" !default;

@include order(150px, $form-selectors...);
游乐场

Sass 语法

$form-selectors: "input.name", "input.address", "input.zip" !default

@include order(150px, $form-selectors...)

💡 有趣的事实

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

游乐场

SCSS 语法

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

Sass 语法

@mixin btn($args...)
  @warn "The btn() mixin is deprecated. Include button() instead."
  @include button($args...)

内容块内容块永久链接

除了接受参数之外,Mixin 还可以接受一个完整的样式块,称为内容块。Mixin 可以通过在其主体中包含 @content at-rule 来声明它接受一个内容块。内容块使用花括号传递,就像 Sass 中的任何其他块一样,它会被注入到 @content 规则的位置。

游乐场

SCSS 语法

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

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

Sass 语法

@mixin hover
  &:not([disabled]):hover
    @content



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


CSS 输出

.button {
  border: 1px solid black;
}
.button:not([disabled]):hover {
  border-width: 2px;
}






💡 有趣的事实

Mixin 可以包含多个 @content at-rule。如果它这样做,内容块将分别为每个 @content 包含。

⚠️ 注意!

内容块是词法作用域的,这意味着它只能看到 包含 Mixin 的作用域中的局部变量。它看不到传递给它的 Mixin 中定义的任何变量,即使这些变量是在调用内容块之前定义的。

向内容块传递参数向内容块传递参数永久链接

兼容性
Dart Sass
自 1.15.0 起
LibSass
Ruby Sass

Mixin 可以像传递给另一个 Mixin 一样向其内容块传递参数,方法是编写 @content(<arguments...>)。编写内容块的用户可以通过编写 @include <name> using (<arguments...>) 来接受参数。内容块的参数列表与 Mixin 的参数列表的工作方式相同,传递给它的参数与传递给 Mixin 的参数的工作方式相同。

⚠️ 注意!

如果 Mixin 向其内容块传递参数,那么该内容块必须声明它接受这些参数。这意味着最好只按位置传递参数(而不是按名称),并且这意味着传递更多参数是一个破坏性变更。

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

游乐场

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;
    }
  }
}
游乐场

Sass 语法

@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



CSS 输出

@media screen {
  h1 {
    font-size: 40px;
  }
}
@media print {
  h1 {
    font-size: 40px;
    font-family: Calluna;
  }
}





缩进 Mixin 语法缩进 Mixin 语法永久链接

缩进语法 除了标准的 @mixin@include 之外,还有一种特殊的语法用于定义和使用 Mixin。Mixin 使用字符 = 定义,使用 + 包含。尽管这种语法更简洁,但它也更难理解,建议用户避免使用它。

游乐场

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

CSS 输出

nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
nav ul li {
  display: inline-block;
  margin-left: -2px;
  margin-right: 2em;
}