@mixin 和 @include
Mixins 允许你定义可以在整个样式表中重复使用的样式。它们使得避免使用非语义类(如 .float-left
)变得容易, 并且可以在库中分发样式集合。
Mixins 使用 @mixin
规则定义,可以写成 @mixin <名称> { ... }
或 @mixin 名称(<参数...>) { ... }
。
Mixin 的名称可以是任何不以 --
开头的 Sass 标识符,并且可以包含除顶层语句之外的任何语句。
它们可以用于封装可以插入单个样式规则的样式;可以包含自己的样式规则,这些规则可以嵌套在其他规则中或包含在样式表的顶层;或者仅用于修改变量。
使用 @include
规则将 Mixins 包含到当前上下文中,写作 @include <名称>
或 @include <名称>(<参数...>)
,
后面跟要包含的 mixin 的名称。
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;
}
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-list
和 reset_list
都指向同一个 mixin。
这是 Sass 早期历史的遗留,当时它仅允许在标识符名称中使用下划线。一旦 Sass 添加了对连字符的支持以匹配 CSS 的语法, 这两者就被设置为等效,以便更容易迁移。
参数参数 permalink
Mixins 还可以接受参数,这允许在每次调用时自定义其行为。参数在 @mixin
规则中的 mixin 名称后指定,
作为用括号括起来的变量名列表。然后必须使用相同数量的参数(以 SassScript 表达式 的形式)包含 mixin。
这些表达式的值在 mixin 的主体中作为相应的变量可用。
SCSS Syntax
@mixin rtl($property, $ltr-value, $rtl-value) {
#{$property}: $ltr-value;
[dir=rtl] & {
#{$property}: $rtl-value;
}
}
.sidebar {
@include rtl(float, left, right);
}
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 变得容易。
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);
}
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, 或具有布尔参数(其含义没有与之相关的名称就不明显)特别有用。关键字参数使用与变量声明和可选参数相同的语法。
SCSS Syntax
@mixin square($size, $radius: 0) {
width: $size;
height: $size;
@if $radius != 0 {
border-radius: $radius;
}
}
.avatar {
@include square(100px, $radius: 4px);
}
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 的所有额外参数都作为列表传递给该参数。这个参数称为参数列表。
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");
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.
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,
)
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!
SCSS Syntax
$form-selectors: "input.name", "input.address", "input.zip" !default;
@include order(150px, $form-selectors...);
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!
SCSS Syntax
@mixin btn($args...) {
@warn "The btn() mixin is deprecated. Include button() instead.";
@include button($args...);
}
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.
SCSS Syntax
@mixin hover {
&:not([disabled]):hover {
@content;
}
}
.button {
border: 1px solid black;
@include hover {
border-width: 2px;
}
}
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
- 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!
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;
}
}
}
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.
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;
}