在 Sass 中,我们可以使用继承、混合和函数来复用一些 CSS 样式和功能。
继承
@extend
继承使用 @extend 指令实现,如
代码语言:javascript复制.error {
border: 1px solid red;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
编译后
代码语言:javascript复制.error, .seriousError {
border: 1px solid red;
background-color: #fdd;
}
.seriousError {
border-width: 3px;
}
实际上,Sass 是将使用 @extend 的 .seriousError 和 .error 编译为了组合选择器 .error, .seriousError。以往我们在 CSS 中复用一段样式时,也会使用 组合选择器 这种形式。
在了解了继承的编译原理之后,我们来看几种复杂情况。
多重继承 (Multiple Extends)
一个选择器可以继承多个选择器。
代码语言:javascript复制.error {
border: 1px #f00;
background-color: #fdd;
}
.attention {
font-size: 3em;
background-color: #ff0;
}
.seriousError {
@extend .error;
@extend .attention;
border-width: 3px;
}
编译后
代码语言:javascript复制.error, .seriousError {
border: 1px #f00;
background-color: #fdd;
}
.attention, .seriousError {
font-size: 3em;
background-color: #ff0;
}
.seriousError {
border-width: 3px;
}
多重继承,会被编译为多个组合选择器。
继承嵌套的选择器列(Selector Sequences)
代码语言:javascript复制.inner {
p {
font-size: 14px;
}
&:hover {
color: red;
}
}
.spec-inner {
@extend .inner;
}
编译后
代码语言:javascript复制.inner p, .spec-inner p {
font-size: 14px;
}
.inner:hover, .spec-inner:hover {
color: red;
}
显然,.spec-inner 在继承 .inner 的时候,也继承了 .inner 的嵌套结构。
继承链 (Chaining Extends)
当出现选择器 C 继承 B,B 继承 A 的情况时,会从 继承链末端 C 开始向上与 B 组合,之后 C、B 再和 A 组合。
代码语言:javascript复制.error {
border: 1px #f00;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
.criticalError {
@extend .seriousError;
position: fixed;
top: 10%;
bottom: 10%;
left: 10%;
right: 10%;
}
编译后
代码语言:javascript复制.error, .seriousError, .criticalError {
border: 1px #f00;
background-color: #fdd;
}
.seriousError, .criticalError {
border-width: 3px;
}
.criticalError {
position: fixed;
top: 10%;
bottom: 10%;
left: 10%;
right: 10%;
}
@extend-only
由于 @extend 可以复用 CSS 的特性,有时我们可能会专门写一些样式给其它选择器继承,而不是为了给具体的元素使用。这时可以使用 占位符选择器,这些选择器不会被编译到 CSS 中。 我们可以使用 % 来标识一个占位符,如
代码语言:javascript复制#context a%extreme {
color: blue;
font-weight: bold;
font-size: 2em;
}
.notice {
@extend %extreme;
}
编译后
代码语言:javascript复制#context a.notice {
color: blue;
font-weight: bold;
font-size: 2em;
}
可以看到,选择器 #context a 并没有被编译输出。
!optional
当我们不确定继承的选择器是否存在时,可以使用 !optional 标识,如
代码语言:javascript复制a.important {
@extend .notice !optional;
}
此时可以成功编译,但由于 .notice 不存在,所以没有任何输出。 如果不加 !optional,编译时会报错:
代码语言:javascript复制"a.important" failed to @extend ".notice"
The selector ".notice" was not found.
Use "@extend .notice !optional" if the extend should be able to fail.
混合
@mixin、@include
在 Sass 中,可以使用 @mixin 封装一段 CSS 代码,之后通过 @include 引入。
代码语言:javascript复制@mixin large-text { // 定义
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
.page-title {
@include large-text; // 引入
padding: 4px;
margin-top: 10px;
}
编译后
代码语言:javascript复制.page-title {
font-family: Arial;
font-size: 20px;
font-weight: bold;
color: #ff0000;
padding: 4px;
margin-top: 10px;
}
参数
我们可以定义接收参数的 mixin,并为参数设置默认值,如
代码语言:javascript复制@mixin sexy-border($color, $width: 1px) {
border: {
color: $color;
width: $width;
style: dashed;
}
}
在引入 mixin 时,可以按顺序传参,也可以指定传入值给哪个参数,如
代码语言:javascript复制h1 {
@include sexy-border(blue, 1px);
}
p {
@include sexy-border($width: 1px, $color: red);
}
编译后
代码语言:javascript复制h1 {
border-color: blue;
border-width: 1px;
border-style: dashed;
}
p {
border-color: red;
border-width: 1px;
border-style: dashed;
}
@content
在使用 mixin 时,我们可以先向 mixin 中导入一段代码,然后再输出混合样式,导入的代码将出现在 @content 标识的位置,这和一些语言和框架中“插槽(slot)”的用法相似。
代码语言:javascript复制@mixin apply-to-ie6-only {
* html {
@content;
}
}
@include apply-to-ie6-only {
#logo {
background-image: url(/logo.gif);
}
}
编译后
代码语言:javascript复制* html #logo {
background-image: url(/logo.gif);
}
编译后,选择器 #logo 及其样式替换了 @content 并插入到了相应的位置。
函数
@function
在 Sass 中,可以使用 @function 定义一个函数,如
代码语言:javascript复制@function grid-width($grid-width, $gutter-width, $n: 5) {
@return $n * $grid-width ($n - 1) * $gutter-width;
}
与 mixin 相似,function 可以接收多个参数,并为参数设置默认值。 在调用时,也可以为指定参数赋值,如
代码语言:javascript复制#sidebar {
width: grid-width($gutter-width: 10px, $grid-width: 40px)
}
编译后
代码语言:javascript复制#sidebar {
width: 240px;
}
mixin 适用于封装一段 CSS 代码,而 function 则更适用于封装一段逻辑或计算过程。