@mixin 和 @include

Mixins 允许你定义可以在整个样式表中重复使用的样式。它们使得避免使用非语义类(如 .float-left)变得容易, 并且可以在库中分发样式集合。

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

使用 @include 规则将 Mixins 包含到当前上下文中,写作 @include <名称>@include <名称>(<参数...>), 后面跟要包含的 mixin 的名称。

Playground

SCSS Syntax

@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;
}
Playground

Sass Syntax

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

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











💡 Fun fact:

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

参数参数 permalink

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

Playground

SCSS Syntax

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

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

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

Sass Syntax

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

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



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

CSS Output

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





💡 Fun fact:

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

可选参数可选参数 permalink

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

Playground

SCSS Syntax

@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);
}
Playground

Sass Syntax

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

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







💡 Fun fact:

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

关键字参数关键字参数 permalink

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

Playground

SCSS Syntax

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

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

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

Sass Syntax

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

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



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

CSS Output

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







⚠️ Heads up!

因为任何参数都可以按名称传递,所以在重命名 mixin 的参数时要小心……这可能会破坏你的用户! 保留旧名称作为可选参数一段时间并在有人传递时打印警告可能会有帮助,以便他们知道要迁移到新参数。

接受任意参数接受任意参数 permalink

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

Playground

SCSS Syntax

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






Playground

Sass Syntax

@mixin order($height, $selectors...)
  @for $i from 0 to length($selectors)
    #{nth($selectors, $i + 1)}
      position: absolute
      height: $height




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







CSS Output

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

Taking Arbitrary Keyword ArgumentsTaking Arbitrary Keyword Arguments permalink

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.

Playground

SCSS Syntax

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

Sass Syntax

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

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

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

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







💡 Fun fact:

If you don’t ever pass an argument list to the meta.keywords() function, that argument list won’t allow extra keyword arguments. This helps callers of your mixin make sure they haven’t accidentally misspelled any argument names.

Passing Arbitrary ArgumentsPassing Arbitrary Arguments permalink

Just like argument lists allow mixins to take arbitrary positional or keyword arguments, the same syntax can be used to pass positional and keyword arguments to a mixin. If you pass a list followed by ... as the last argument of an include, its elements will be treated as additional positional arguments. Similarly, a map followed by ... will be treated as additional keyword arguments. You can even pass both at once!

Playground

SCSS Syntax

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

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

Sass Syntax

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

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

💡 Fun fact:

Because an argument list keeps track of both positional and keyword arguments, you use it to pass both at once to another mixin. That makes it super easy to define an alias for a mixin!

Playground

SCSS Syntax

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

Sass Syntax

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

Content BlocksContent Blocks permalink

In addition to taking arguments, a mixin can take an entire block of styles, known as a content block. A mixin can declare that it takes a content block by including the @content at-rule in its body. The content block is passed in using curly braces like any other block in Sass, and it’s injected in place of the @content rule.

Playground

SCSS Syntax

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

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

Sass Syntax

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



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


CSS Output

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






💡 Fun fact:

A mixin can include multiple @content at-rules. If it does, the content block will be included separately for each @content.

⚠️ Heads up!

A content block is lexically scoped, which means it can only see local variables in the scope where the mixin is included. It can’t see any variables that are defined in the mixin it’s passed to, even if they’re defined before the content block is invoked.

Passing Arguments to Content BlocksPassing Arguments to Content Blocks permalink

Compatibility:
Dart Sass
since 1.15.0
LibSass
Ruby Sass

A mixin can pass arguments to its content block the same way it would pass arguments to another mixin by writing @content(<arguments...>). The user writing the content block can accept arguments by writing @include <name> using (<arguments...>). The argument list for a content block works just like a mixin’s argument list, and the arguments passed to it by @content work just like passing arguments to a mixin.

⚠️ Heads up!

If a mixin passes arguments to its content block, that content block must declare that it accepts those arguments. This means that it’s a good idea to only pass arguments by position (rather than by name), and it means that passing more arguments is a breaking change.

If you want to be flexible in what information you pass to a content block, consider passing it a map that contains information it may need!

Playground

SCSS Syntax

@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;
    }
  }
}
Playground

Sass Syntax

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

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





Indented Mixin SyntaxIndented Mixin Syntax permalink

The indented syntax has a special syntax for defining and using mixins, in addition to the standard @mixin and @include. Mixins are defined using the character =, and they’re included using +. Although this syntax is terser, it’s also harder to understand at a glance and users are encouraged to avoid it.

Playground

Sass Syntax

=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 Output

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