@mixin 和 @include
混合宏允许你定义可以在整个样式表中重复使用的样式。它们使得避免使用 .float-left 等非语义类,以及在库中分发样式集合变得容易。
混合宏使用 @mixin at-rule 定义,其写法为 @mixin <name> { ... } 或 @mixin name(<arguments...>) { ... }。混合宏的名称可以是任何不以 -- 开头的 Sass 标识符,并且它可以包含除顶层语句之外的任何语句。它们可以用来封装可以放入单个样式规则中的样式;它们可以包含自己的样式规则,这些规则可以嵌套在其他规则中,或包含在样式表的顶层;或者它们只是用于修改变量。
混合宏使用 @include at-rule 包含到当前上下文中,其写法为 @include <name> 或 @include <name>(<arguments...>),其中 <name> 是要包含的混合宏的名称。
@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 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
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav ul li {
display: inline-block;
margin-left: -2px;
margin-right: 2em;
}
reset-list 和 reset_list 都指同一个混合宏。这是 Sass 早期的历史遗留问题,当时它只允许在标识符名称中使用下划线。一旦 Sass 添加了对连字符的支持以匹配 CSS 的语法,两者就被设置为等效,以使迁移更容易。参数
混合宏也可以接受参数,这允许在每次调用时自定义它们的行为。参数在 @mixin 规则中,在混合宏名称后,以圆括号括起来的变量名列表的形式指定。然后,必须使用相同数量的参数(以 SassScript 表达式的形式)来包含混合宏。这些表达式的值在混合宏主体中作为相应的变量可用。
@mixin rtl($property, $ltr-value, $rtl-value) {
#{$property}: $ltr-value;
[dir=rtl] & {
#{$property}: $rtl-value;
}
}
.sidebar {
@include rtl(float, left, right);
}
@mixin rtl($property, $ltr-value, $rtl-value)
#{$property}: $ltr-value
[dir=rtl] &
#{$property}: $rtl-value
.sidebar
@include rtl(float, left, right)
.sidebar {
float: left;
}
[dir=rtl] .sidebar {
float: right;
}
可选参数
通常,混合宏声明的每个参数都必须在包含该混合宏时传递。但是,你可以通过定义一个默认值来使参数可选,如果该参数未传递,则将使用该默认值。默认值使用与变量声明相同的语法:变量名,后跟一个冒号和一个 SassScript 表达式。这使得定义灵活的混合宏 API 变得容易,它们可以以简单或复杂的方式使用。
@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);
}
@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)
.mail-icon {
text-indent: -99999em;
overflow: hidden;
text-align: left;
background-image: url("/images/mail.svg");
background-repeat: no-repeat;
background-position: 0 50%;
}
关键字参数
当包含一个混合宏时,除了按其在参数列表中的位置传递参数外,还可以按名称传递参数。这对于具有多个可选参数或具有布尔参数的混合宏特别有用,如果没有名称,它们的含义就不那么明显。关键字参数使用与变量声明和可选参数相同的语法。
@mixin square($size, $radius: 0) {
width: $size;
height: $size;
@if $radius != 0 {
border-radius: $radius;
}
}
.avatar {
@include square(100px, $radius: 4px);
}
@mixin square($size, $radius: 0)
width: $size
height: $size
@if $radius != 0
border-radius: $radius
.avatar
@include square(100px, $radius: 4px)
.avatar {
width: 100px;
height: 100px;
border-radius: 4px;
}
接受任意参数
有时,让一个混合宏能够接受任意数量的参数会很有用。如果 @mixin 声明中的最后一个参数以 ... 结尾,那么传递给该混合宏的所有额外参数都将作为列表传递给该参数。这个参数被称为参数列表。
@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");
@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")
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() 函数接受一个参数列表,并返回作为映射传递给混合宏的任何额外关键字,该映射从参数名(不包括 $) 映射到这些参数的值。
@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,
)
@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)
pre span.stx-string {
color: #080;
}
pre span.stx-comment {
color: #800;
}
pre span.stx-variable {
color: #60b;
}
meta.keywords() 函数,则该参数列表将不允许额外的关键字参数。这有助于混合宏的调用者确保他们没有意外拼错任何参数名称。传递任意参数
就像参数列表允许混合宏接受任意位置或关键字参数一样,相同的语法可用于传递位置和关键字参数给混合宏。如果你将一个列表后跟 ... 作为包含的最后一个参数,其元素将被视为额外的位置参数。同样,后跟 ... 的映射将被视为额外的关键字参数。你甚至可以同时传递两者!
$form-selectors: "input.name", "input.address", "input.zip" !default;
@include order(150px, $form-selectors...);
$form-selectors: "input.name", "input.address", "input.zip" !default
@include order(150px, $form-selectors...)
@mixin btn($args...) {
@warn "The btn() mixin is deprecated. Include button() instead.";
@include button($args...);
}
@mixin btn($args...)
@warn "The btn() mixin is deprecated. Include button() instead."
@include button($args...)
内容块
除了接受参数外,混合宏还可以接受一整个样式块,称为内容块。混合宏可以通过在其主体中包含 @content at-rule 来声明它接受一个内容块。内容块使用大括号传入,就像 Sass 中的任何其他块一样,它被注入到 @content 规则的位置。
@mixin hover {
&:not([disabled]):hover {
@content;
}
}
.button {
border: 1px solid black;
@include hover {
border-width: 2px;
}
}
@mixin hover
&:not([disabled]):hover
@content
.button
border: 1px solid black
@include hover
border-width: 2px
.button {
border: 1px solid black;
}
.button:not([disabled]):hover {
border-width: 2px;
}
@content at-rule。如果它包含多个,内容块将为每个 @content 分别包含。向内容块传递参数
一个混合宏可以向其内容块传递参数,其方式与向另一个混合宏传递参数的方式相同,即编写 @content(<arguments...>)。编写内容块的用户可以通过编写 @include <name> using (<arguments...>) 来接受参数。内容块的参数列表就像混合宏的参数列表一样工作,而由 @content 传递给它的参数就像传递给混合宏的参数一样工作。
@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 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
@media screen {
h1 {
font-size: 40px;
}
}
@media print {
h1 {
font-size: 40px;
font-family: Calluna;
}
}
缩进混合宏语法
除了标准的 @mixin 和 @include 之外,缩进语法还有一种特殊的语法来定义和使用混合宏。混合宏使用字符 = 定义,并使用 + 包含。虽然这种语法更简洁,但它也更难一眼看懂,因此鼓励用户避免使用它。
=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
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav ul li {
display: inline-block;
margin-left: -2px;
margin-right: 2em;
}