特性
变量是sass
提供的最基本的工具。通过变量可以让独立的css
值变得可重用,无论是在一条单独的规则范围内还是在整个样式表中。变量、混合器的命名甚至sass的文件名,可以互换通用_
和-
。
sass
的嵌套机制。嵌套允许css
规则内嵌套css
规则,减少重复编写常用的选择器,同时让样式表的结构一眼望去更加清晰。sass同时提供了特殊的父选择器标识符&,通过它可以构造出更高效的嵌套。
通过样式导入可以把分散在多个sass
文件中的内容合并生成到一个css
文件,避免了项目中有大量的css
文件通过原生的css @import
带来的性能问题。通过嵌套导入和默认变量值,导入可以构建更强有力的、可定制的样式。
混合器允许用户编写语义化样式的同时避免视觉层面上样式的重复,使css变得更加可维护和语义化。
选择器继承。继承允许声明类之间语义化的关系。
Sass简述
使用$
符号来标识变量,可以大大减少了工作量
与CSS
属性不同,变量可以在css
规则块定义之外存在。当变量定义在css
规则块内,那么该变量只能在此规则块内使用。
当包含父选择器标识符的嵌套规则被打开时,它不会像后代选择器那样进行拼接,而是&
被父选择器直接替换
可以在父选择器之前添加选择器
在一个特定的容器元素内对群组选择器.button, button
进行修饰,使用sass
的嵌套特性:
.button {
button1, button2, button3 {margin-bottom: .8em}
}
子组合选择器和同层组合选择器:>、+和~
必须和其他选择器配合使用
子组合选择器>:选择一个元素的直接子元素
同层相邻组合选择器+
:选择header
元素后紧跟的p
元素
同层全体组合选择器~
:选择所有跟在article
后的同层article
元素,不管它们之间隔了多少其他元素
嵌套属性
如:只需敲写一遍border
nav {
border: {
style: solid;
width: 1px;
color: #ccc;
}
}
规则:把属性名从中划线-的地方断开,在根属性后边添加一个冒号:,紧跟一个{ }
块,把子属性部分写在这个{ }
块中。就像css
选择器嵌套一样,sass
会把你的子属性一一解开,把根属性和子属性部分通过中划线-连接起来
拆分多个文件
sass
通过对css
原有@import
规则的改进直接支持了这一特性
sass
的@import
规则在生成css
文件时就把相关文件导入进来,和css
特性中只有执行到@import
时,浏览器才会去下载其他css
文件不同。
导入时可以省略.sass
或.scss
文件后缀
使用Sass部分文件
命名局部文件:以下划线开头
这样,sass
就不会在编译时单独编译这个文件输出css
,而只把这个文件用作导入。
当你@import
一个局部文件时,还可以不写文件的全名,即省略文件名开头的下划线。
默认变量值
有时需要在你的样式表中对导入的样式稍作修改,sass
有一个功能刚好可以解决这个问题,即默认变量值。
使用!default
实现:导入者可以定制修改sass
库文件中的某些值。
它很像css
属性中!important
标签的对立面,不同的是!default
用于变量,含义是:如果这个变量被声明赋值了,那就用它声明的值,否则就用这个默认值。
嵌套导入
允许只在某一个选择器的范围内导入sass
局部文件。
sass
允许@import
命令写在css
规则内
如:
.blue-theme {@import "blue-theme"}
原生CSS导入
有时,可用css
原生的@import
机制,在浏览器中下载必需的css
文件。
下列三种情况下会生成原生的CSS@import
,尽管这会造成浏览器解析css
时的额外下载:
- 被导入文件的名字以
.css
结尾; - 被导入文件的名字是一个URL地址(比如http://www.sass.hk/css/css.css),由此可用谷歌字体API提供的相应服务;
- 被导入文件的名字是
CSS
的url()值。
不能用
sass
的@import
直接导入一个原始的css
文件,因为sass
会认为你想用css
原生的@import
。
静默注释
不希望每一个浏览网站源码的人都能看到所有注释
静默注释的语法跟JavaScript
Java
等类C
的语言中单行注释的语法相同,它们以//
开头,注释内容直到行末。
注:css
的标准注释格式/* ... */
注释出现在原生css
不允许的地方,如在css
属性或选择器中,sass
将不知如何将其生成到对应css
文件中的相应位置,于是这些注释被抹掉。
以上,介绍了保持sass
条理性和可读性的最基本的三个方法:
- 嵌套
- 导入
- 注释
使用混合器抽象相关样式
如果整个项目中有几处小小的样式:一致的颜色和字体,那么最好使用变量来统一处理。如果样式变得越来越复杂,就可以通过sass
的混合器实现大段样式的重用。
- 使用
@mixin
标识符定义。给一大段样式赋予一个名字。
例如:添加跨浏览器的圆角边框
@mixin rounded-corners {
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
- 通过
@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;
}
那么如何防止过度使用呢?
混合器的使用场景
一条经验法则就是能否为这个混合器想出一个好的名字。
CSS类和混合器区别
最重要的区别就是类名是在html
文件中应用的,而混合器是在样式表中应用的。
这就意味着类名具有语义化含义,而不仅仅是一种展示性的描述:用来描述html
元素的含义而不是html
元素的外观。而另一方面,混合器是展示性的描述,用来描述一条css
规则应用之后会产生怎样的效果。
有时候仅仅把属性放在混合器中是远远不够的,sass
同样允许你把css
规则放在混合器中。
混合器中的CSS规则
如果一个混合器只包含css
规则,不包含属性,那么这个混合器就可以在文档的顶部调用,写在所有的css
规则之外。如果你只是为自己写一些混合器,这并没有什么大的用途,但是当你使用一个类似于Compass
的库时,你会发现,这是提供样式的好方法,原因在于你可以选择是否使用这些样式。
混合器如何传参
混合器并不一定总得生成相同的样式。可以通过在@include
混合器时给混合器传参,来定制混合器生成的精确样式。当@include
混合器时,参数其实就是可以赋值给css
属性值的变量。这种方式跟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; }
有时很难区分每一个参数是什么意思,为了解决这个问题,sass
允许通过语法$name: value
的形式指定每个参数的值。这种形式的传参,参数顺序就不必再在乎了,只需要保证没有漏掉参数即可:
a {
@include link-colors(
$normal: blue,
$visited: green,
$hover: red
);
}
默认参数值
参数定制固然很好,但是有时候我们没有定制的需要。所以sass
允许混合器声明时给参数赋默认值。
@mixin link-colors(
$normal,
$hover: $normal,
$visited: $normal
)
{
color: $normal;
&:hover { color: $hover; }
&:visited { color: $visited; }
}
像这样调用:@include link-colors(red)
$hover
和$visited
也会被自动赋值为red
。
总结,混合器主要用于样式展示层的重用。
选择器继承
想重用语义化的类。
通过@extend
语法实现
基于Nicole Sullivan
面向对象的css
的理念,选择器继承是说一个选择器可以继承为另一个选择器定义的所有样式。
//通过选择器继承继承样式
.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
元素内的超链接也会变成红色和粗体。
本节将介绍与混合器相比,哪种情况下更适合用继承。接下来在探索继承的工作细节之前,我们先了解一下继承的高级用法。最后,我们将看看使用继承可能会有哪些坑,学习如何避免这些坑。
何时使用继承
混合器主要用于展示性样式的重用,而类名用于语义化样式的重用。因为继承是基于类的(有时是基于其他类型的选择器),所以继承应该是建立在语义化的关系上。当一个元素拥有的类(比如说.seriousError
)表明它属于另一个类(比如说.error
),这时使用继承再合适不过了。
这有点抽象,所以我们从几个方面来阐释一下。想象一下你正在编写一个页面,给html
元素添加类名,你发现你的某个类(比如说.seriousError
)另一个类(比如说.error
)的细化。你会怎么做?
- 你可以为这两个类分别写相同的样式,但是如果有大量的重复怎么办?使用
sass
时,我们提倡的就是不要做重复的工作。 - 你可以使用一个选择器组(比如说
.error
.seriousError
)给这两个选择器写相同的样式。如果.error的所有样式都在同一个地方,这种做法很好,但是如果是分散在样式表的不同地方呢?再这样做就困难多了。 - 你可以使用一个混合器为这两个类提供相同的样式,但当
.error
的样式修饰遍布样式表中各处时,这种做法面临着跟使用选择器组一样的问题。这两个类也不是恰好有相同的 样式。你应该更清晰地表达这种关系。 - 综上所述你应该使用
@extend
。让.seriousError
从.error
继承样式,使两者之间的关系非常清晰。更重要的是无论你在样式表的哪里使用.error
.seriousError
都会继承其中的样式。
现在你已经更好地掌握了何时使用继承,以及继承有哪些突出的优点,接下来我们看看一些高级用法。
继承的高级用法
任何css
规则都可以继承其他规则,几乎任何css
规则也都可以被继承。大多数情况你可能只想对类使用继承,但是有些场合你可能想做得更多。最常用的一种高级用法是继承一个html
元素的样式。尽管默认的浏览器样式不会被继承,因为它们不属于样式表中的样式,但是你对html
元素添加的所有样式都会被继承。
接下来的这段代码定义了一个名为disabled
的类,样式修饰使它看上去像一个灰掉的超链接。通过继承a这一超链接元素来实现:
.disabled {
color: gray;
@extend a;
}
假如一条样式规则继承了一个复杂的选择器,那么它只会继承这个复杂选择器命中的元素所应用的样式。举例来说, 如果.seriousError @extend .important.error
, 那么.important.error
和h1.important.error
的样式都会被.seriousError
继承, 但是.important
或者.error下
的样式则不会被继承。这种情况下你很可能希望.seriousError
能够分别继承.important
或者.error
下的样式。
如果一个选择器序列(#main .seriousError
)@extend
另一个选择器(.error
),那么只有完全匹配#main .seriousError
这个选择器的元素才会继承.error
的样式,就像单个类名继承那样。拥有class="seriousError"
的#main
元素之外的元素不会受到影响。
像#main .error
这种选择器序列是不能被继承的。这是因为从#main .error
中继承的样式一般情况下会跟直接从.error
中继承的样式基本一致,细微的区别往往使人迷惑。
现在你已经了解了通过继承能够做些什么事情,接下来我们将学习继承的工作细节,在生成对应css
的时候,sass
具体干了些什么事情。
继承的工作细节
跟变量和混合器不同,继承不是仅仅用css
样式替换@extend处的代码那么简单。为了不让你对生成的css
感觉奇怪,对这背后的工作原理有一定了解是非常重要的。
@extend
背后最基本的想法是,如果.seriousError @extend .error
, 那么样式表中的任何一处.error
都用.error
.seriousError
这一选择器组进行替换。这就意味着相关样式会如预期那样应用到.error
和.seriousError
。当.error
出现在复杂的选择器中,比如说h1.error
.error a
或者#main .sidebar input.error[type="text"]
,那情况就变得复杂多了,但是不用担心,sass
已经为你考虑到了这些。
关于@extend
有两个要点你应该知道。
- 跟混合器相比,继承生成的
css
代码相对更少。因为继承仅仅是重复选择器,而不会重复属性,所以使用继承往往比混合器生成的css
体积更小。如果你非常关心你站点的速度,请牢记这一点。 - 继承遵从
css
层叠的规则。当两个不同的css
规则应用到同一个html
元素上时,并且这两个不同的css
规则对同一属性的修饰存在不同的值,css
层叠规则会决定应用哪个样式。相当直观:通常权重更高的选择器胜出,如果权重相同,定义在后边的规则胜出。
混合器本身不会引起css
层叠的问题,因为混合器把样式直接放到了css
规则中,而继承存在样式层叠的问题。被继承的样式会保持原有定义位置和选择器权重不变。通常来说这并不会引起什么问题,但是知道这点总没有坏处。
使用继承的最佳实践
通常使用继承会让你的css
美观、整洁。因为继承只会在生成css
时复制选择器,而不会复制大段的css
属性。但是如果你不小心,可能会让生成的css
中包含大量的选择器复制。
避免这种情况出现的最好方法就是不要在css
规则中使用后代选择器(比如.foo .bar
)去继承css
规则。如果你这么做,同时被继承的css
规则有通过后代选择器修饰的样式,生成css
中的选择器的数量很快就会失控:
.foo .bar { @extend .baz; }
.bip .baz { a: b; }
在上边的例子中,sass
必须保证应用到.baz的样式同时也要应用到.foo .bar
(位于class="foo"的元素内的class="bar"的元素)。例子中有一条应用到.bip .baz
(位于class="bip"的元素内的class="baz"的元素)的css
规则。当这条规则应用到.foo .bar
时,可能存在三种情况,如下代码:
为了应付这些情况,sass
必须生成三种选择器组合(仅仅是.bip .foo .bar不能覆盖所有情况)。如果任何一条规则里边的后代选择器再长一点,sass
需要考虑的情况就会更多。实际上sass
并不总是会生成所有可能的选择器组合,即使是这样,选择器的个数依然可能会变得相当大,所以如果允许,尽可能避免这种用法。
值得一提的是,只要你想,你完全可以放心地继承有后代选择器修饰规则的选择器,不管后代选择器多长,但有一个前提就是,不要用后代选择器去继承。