原文链接: SASS 混合器和继承
上一篇: SASS 导入
下一篇: vue-tinymce-editor markdown 在线编辑器
混合器使用 @mixin
标识符定义。看上去很像其他的 CSS @
标识符,比如说 @media
或者 @font-face
。这个标识符给一大段样式赋予一个名字,这样你就可以轻易地通过引用这个名字重用这段样式。
@mixin rounded-corners {
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
然后就可以在你的样式表中通过 @include
来使用这个混合器,放在你希望的任何地方。 @include
调用会把混合器中的所有样式提取出来放在 @include
被调用的地方。如果像下边这样写:
notice {
background-color: green;
border: 2px solid #00aa00;
@include rounded-corners;
}
//sass最终生成:
.notice {
background-color: green;
border: 2px solid #00aa00;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
大量的重用可能会导致生成的样式表过大,导致加载缓慢。所以,首先我们将讨论混合器的使用场景,避免滥用。
何时使用混合器;
利用混合器,可以很容易地在样式表的不同地方共享样式。如果你发现自己在不停地重复一段样式,那就应该把这段样式构造成优良的混合器,尤其是这段样式本身就是一个逻辑单元,比如说是一组放在一起有意义的属性。
判断一组属性是否应该组合成一个混合器,一条经验法则就是你能否为这个混合器想出一个好的名字。如果你能找到一个很好的短名字来描述这些属性修饰的样式,比如 rounded-corners
fancy-font
或者 no-bullets
,那么往往能够构造一个合适的混合器。如果你找不到,这时候构造一个混合器可能并不合适。
混合器在某些方面跟 css
类很像。都是让你给一大段样式命名,所以在选择使用哪个的时候可能会产生疑惑。最重要的区别就是类名是在 html
文件中应用的,而混合器是在样式表中应用的。这就意味着类名具有语义化含义,而不仅仅是一种展示性的描述:用来描述 html
元素的含义而不是 html
元素的外观。而另一方面,混合器是展示性的描述,用来描述一条 css
规则应用之后会产生怎样的效果。
在之前的例子中, .notice
是一个有语义的类名。如果一个 html
元素有一个 notice
的类名,就表明了这个 html
元素的用途:向用户展示提醒信息。 rounded-corners
混合器是展示性的,它描述了包含它的 css
规则最终的视觉样式,尤其是边框角的视觉样式。混合器和类配合使用写出整洁的 html
和 css
,因为使用语义化的类名亦可以帮你避免重复使用混合器。为了保持你的 html
和 css
的易读性和可维护性,在写样式的过程中一定要铭记二者的区别。
有时候仅仅把属性放在混合器中还远远不够,可喜的是, sass
同样允许你把 css
规则放在混合器中。
混合器中的CSS规则;
混合器中不仅可以包含属性,也可以包含 css
规则,包含选择器和选择器中的属性,如下代码:
@mixin no-bullets {
list-style: none;
li {
list-style-image: none;
list-style-type: none;
margin-left: 0px;
}
}
当一个包含 css
规则的混合器通过 @include
包含在一个父规则中时,在混合器中的规则最终会生成父规则中的嵌套规则。举个例子,看看下边的 sass
代码,这个例子中使用了 no-bullets
这个混合器:
ul.plain {
color: #444;
@include no-bullets;
}
sass
的 @include
指令会将引入混合器的那行代码替换成混合器里边的内容。最终,上边的例子如下代码:
ul.plain {
color: #444;
list-style: none;
}
ul.plain li {
list-style-image: none;
list-style-type: none;
margin-left: 0px;
}
混合器中的规则甚至可以使用 sass
的父选择器标识符 &
。使用起来跟不用混合器时一样, sass
解开嵌套规则时,用父规则中的选择器替代 &
。
如果一个混合器只包含 css
规则,不包含属性,那么这个混合器就可以在文档的顶部调用,写在所有的 css
规则之外。如果你只是为自己写一些混合器,这并没有什么大的用途,但是当你使用一个类似于 Compass
的库时,你会发现,这是提供样式的好方法,原因在于你可以选择是否使用这些样式。
接下来你将学习如何通过给混合器传参数来让混合器变得更加灵活和可重用。
给混合器传参;
混合器并不一定总得生成相同的样式。可以通过在 @include
混合器时给混合器传参,来定制混合器生成的精确样式。当 @include
混合器时,参数其实就是可以赋值给 css
属性值的变量。如果你写过 JavaScript
,这种方式跟 JavaScript
的 function
很像:
@mixin link-colors($normal, $hover, $visited) {
color: $normal;
&:hover { color: $hover; }
&:visited { color: $visited; }
}
当混合器被 @include
时,你可以把它当作一个 css
函数来传参。如果你像下边这样写:
a {
@include link-colors(blue, red, green);
}
//Sass最终生成的是:
a { color: blue; }
a:hover { color: red; }
a:visited { color: green; }
当你@include混合器时,有时候可能会很难区分每个参数是什么意思,参数之间是一个什么样的顺序。为了解决这个问题, sass
允许通过语法 $name: value
的形式指定每个参数的值。这种形式的传参,参数顺序就不必再在乎了,只需要保证没有漏掉参数即可:
a {
@include link-colors(
$normal: blue,
$visited: green,
$hover: red
);
}
尽管给混合器加参数来实现定制很好,但是有时有些参数我们没有定制的需要,这时候也需要赋值一个变量就变成很痛苦的事情了。所以 sass
允许混合器声明时给参数赋默认值。
默认参数值;
为了在 @include
混合器时不必传入所有的参数,我们可以给参数指定一个默认值。参数默认值使用 $name: default-value
的声明形式,默认值可以是任何有效的 css
属性值,甚至是其他参数的引用,如下代码:
@mixin link-colors(
$normal,
$hover: $normal,
$visited: $normal
)
{
color: $normal;
&:hover { color: $hover; }
&:visited { color: $visited; }
}
如果像下边这样调用: @include link-colors(red)
$hover
和 $visited
也会被自动赋值为 red
。
混合器只是 sass
样式重用特性中的一个。我们已经了解到混合器主要用于样式展示层的重用,如果你想重用语义化的类呢?这就涉及 sass
的另一个重要的重用特性:选择器继承。
使用选择器继承来精简CSS;
使用 sass
的时候,最后一个减少重复的主要特性就是选择器继承。基于 Nicole Sullivan
面向对象的 css
的理念,选择器继承是说一个选择器可以继承为另一个选择器定义的所有样式。这个通过 @extend
语法实现,如下代码:
//通过选择器继承继承样式
.error {
border: 1px solid red;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
在上边的代码中, .seriousError
将会继承样式表中任何位置处为 .error
定义的所有样式。以 class="seriousError"
修饰的 html
元素最终的展示效果就好像是 class="seriousError error"
。相关元素不仅会拥有一个 3px
宽的边框,而且这个边框将变成红色的,这个元素同时还会有一个浅红色的背景,因为这些都是在 .error
里边定义的样式。
.seriousError
不仅会继承 .error
自身的所有样式,任何跟 .error
有关的组合选择器样式也会被 .seriousError
以组合选择器的形式继承,如下代码:
//.seriousError从.error继承样式
.error a{ //应用到.seriousError a
color: red;
font-weight: 100;
}
h1.error { //应用到hl.seriousError
font-size: 1.2rem;
}
如上所示,在 class="seriousError"
的 html
元素内的超链接也会变成红色和粗体。
本节将介绍与混合器相比,哪种情况下更适合用继承。接下来在探索继承的工作细节之前,我们先了解一下继承的高级用法。最后,我们将看看使用继承可能会有哪些坑,学习如何避免这些坑。
何时使用继承;
5-1节介绍了 混合器 主要用于展示性样式的重用,而类名用于语义化样式的重用。因为继承是基于类的(有时是基于其他类型的选择器),所以继承应该是建立在语义化的关系上。当一个元素拥有的类(比如说 .seriousError
)表明它属于另一个类(比如说 .error
),这时使用继承再合适不过了。
这有点抽象,所以我们从几个方面来阐释一下。想象一下你正在编写一个页面,给 html
元素添加类名,你发现你的某个类(比如说 .seriousError
)另一个类(比如说 .error
)的细化。你会怎么做?
- 你可以为这两个类分别写相同的样式,但是如果有大量的重复怎么办?使用
sass
时,我们提倡的就是不要做重复的工作。 - 你可以使用一个选择器组(比如说
.error
.seriousError
)给这两个选择器写相同的样式。如果.error的所有样式都在同一个地方,这种做法很好,但是如果是分散在样式表的不同地方呢?再这样做就困难多了。 - 你可以使用一个混合器为这两个类提供相同的样式,但当
.error
的样式修饰遍布样式表中各处时,这种做法面临着跟使用选择器组一样的问题。这两个类也不是恰好有相同的 样式。你应该更清晰地表达这种关系。 - 综上所述你应该使用
@extend
。让.seriousError
从.error
继承样式,使两者之间的关系非常清晰。更重要的是无论你在样式表的哪里使用.error
.seriousError
都会继承其中的样式。
关于 @extend
有两个要点你应该知道。
- 跟混合器相比,继承生成的
css
代码相对更少。因为继承仅仅是重复选择器,而不会重复属性,所以使用继承往往比混合器生成的css
体积更小。如果你非常关心你站点的速度,请牢记这一点。 - 继承遵从
css
层叠的规则。当两个不同的css
规则应用到同一个html
元素上时,并且这两个不同的css
规则对同一属性的修饰存在不同的值,css
层叠规则会决定应用哪个样式。相当直观:通常权重更高的选择器胜出,如果权重相同,定义在后边的规则胜出。
混合器本身不会引起 css
层叠的问题,因为混合器把样式直接放到了 css
规则中,而继承存在样式层叠的问题。被继承的样式会保持原有定义位置和选择器权重不变。通常来说这并不会引起什么问题,但是知道这点总没有坏处。