@Shel
2017-09-02T06:40:49.000000Z
字数 5336
阅读 1254
Sass
CSS
Compass
本篇重点
- 变量需要先声明后使用,且不存在变量提升。
- 嵌套使得样式结构清晰。
- 利用导入来分离代码,优化文件组织。
- 使用混合器封装重用的样式。
- 使用选择器继承减少样式重复。
SASS使用 $
符号来标志变量。变量遵循先声明后使用的原则。
body {
font-size: $normal-size;
}
$normal-size: 14px;
// 编译代码将会得到错误输出
// Undefined variable: "$normal-size".
变量的声明具有作用域,我们甚至可以多次定义同一个变量的值。看下面的例子:
$normal-size: 14px;
body {
$normal-size: 12px;
font-size: $normal-size;
}
p {
font-size: $normal-size;
}
$normal-size: 12px;
h6 {
font-size: $normal-size;
}
编译后:
body {
font-size: 12px;
}
p {
font-size: 14px;
}
h6 {
font-size: 12px;
}
在上面例子中,body
内部声明的变量仅仅在其内部产生作用,同样的变量在p
使用时没有被影响,然而,在同一作用域内,再次定义变量的值,只会影响后面的规则,前面的规则却没有被影响,这就是为何h6
与p
字号结果不一。可见 SASS 的编译过程是从上到下依次执行的,但与 js 不一样的是它不存在变量的提升。
它的基本原理是:变量被值替换。
嵌套的存在使得我们编写规则更加直观,层次结构十分清晰。就像是在 html
标签之间相互嵌套一般。嵌套是为解决重复书写的问题。先来个直观的感受:
// 在 CSS 中我们使用下面的形式来描述层级结构的样式
article h1 {
color: #333;
}
article p {
color: #eee;
}
// SASS 使用嵌套写法
article {
h1 { color: #333 }
p { color: #eee }
}
这样的写法让我们很容易联想到DOM。
它的原理十分简单:当父选择器内存在子选择器的时候,SASS会将子选择(包括其内的规则)抽出,然后将父选择器放在子选择器前,并用一个空格将二者连接起来。
但有的时候我们并不希望使用空格连接,比如:
a {
color: red;
}
a:hover {
color: green;
}
// 想要编译出上面的CSS,如果使用普通的嵌套写法
a {
color: red;
:hover { color: green }
}
// 编译后
a {
color: red;
}
a :hover {
color: green;
}
很显然,伪类是不能直接嵌套书写的。
默认的前后选择器之间的连接是存在一个空格的,如果想要消除它,可以使用 &
符号。官方将它叫做父选择器,笔者给它起了一个接地气的名字:粘贴符😛,顾名思义,它会将前后两者紧紧的粘在一起,因此上述 SASS 正确的写法是:
a {
color: red;
&:hover { color: green }
}
除了重复书写选择器,重复书写属性名也是十分繁琐的工作。例如
nav {
border-style: solid;
border-width: 1px;
border-color: #ccc;
}
nav {
border: solid 1px #ccc;
border-left: 0;
}
SASS的嵌套语法同样可以作用于属性名,只不过这回使用的连接符号不是空格而是 -
符号。
nav {
border: {
style: solid;
width: 1px;
color: #ccc;
}
}
nav {
border: solid 1px #ccc {
left: 0;
}
}
上述一直在讲述如何使用嵌套语法来简化我们的工作,但别忘了它给我们带来的另一大益处是,直观的视觉缩进使得结构清晰,行文优雅,易于阅读。
SASS的导入命令是在预编译阶段完成的,这有利于我们更好的组织管理样式文件。我们约定,在文件的开头使用 @import
命令导入外部文件。
有些文件是专门为了整合 @import
命令而编写的,并不需要编译成CSS文件,这样的文件官方称之为局部文件。
并且约定,这样的文件名以下划线开头,而在导入时,省略开头的下划线。
“导入”的存在使得变量声明结果不可预料,一般来说,后者覆盖前者。当为变量声明添加额外的 !default
标签时,意味着该值是变量的默认值,默认值的优先级是最低的,无论它在何处声明。
另外,CSS中存在也存在 @import
,为了将两者区分开来,SASS的导入命令只针对SASS文件有效,凡以.sass
或者.scss
结尾的文件都可以在预编译阶段完成导入操作,而已 .css
结尾的文件会被保留下来,作为原生的CSS导入。如果你希望在预编译阶段导入CSS文件,不妨将.css
后缀改成.scss
后缀。
SASS 支持两种注释方式,一种是 CSS 标准注释,即/*...*/
。
另外一种类似于 JS 中的单行注释,以 //
开头一直到行末,这种注释方式称为静默注释,是用这种方式书写的注释会在预编译阶段自动抹去。
如果读者曾经接触过 Less
,那么这个概念你一定不会陌生。就如同 JS 中的函数一样,在样式的世界里,我们将重复使用的属性、规则包装在一个混合器中,并用 @mixin
来声明,然后在需要的地方,使用 @include
调用。先让我们来一个例子,直观的感受一下。
@mixin no-bullets {
list-style: none;
li {
list-style: {
image: none;
type: none;
}
margin: 0;
}
}
ul.plain {
@include no-bullets;
}
// 编译成CSS
ul.plain {
list-style: none;
}
ul.plain li {
list-style-image: none;
list-style-type: none;
margin: 0;
}
使用混合器最终目的是让它返回一堆属性和规则。
同时,我们还可以给它传递参数,使它输出不同的结果。
就如同 js 中函数的参数一样,混合器的参数其实就是在混合器内部声明的局部变量,我们可以在声明时给参数附上默认值。
而在调用混合器时,采用模式匹配给参数赋值。
@mixin link-colors($normal,$hover:$normal,$visited:$normal) {
color: $normal;
&:hover { color: $hover; }
&:visited { color: $visited; }
}
a {
@include link-colors($normal: red,$hover: blue);
}
// 编译后的CSS
a {
color: red;
}
a:hover {
color: blue;
}
a:visited {
color: red;
}
混合器很强大,就如同函数在 js 中一样的地位一样。然而无休止的滥用混合器会导致项目难以维护。
When you have only one hammer in your hand, you tend to look at all the problems as nails.
—— Maslow
一条经验法则:你能否为这个混合器找到一个短名字来描述这些属性修饰的样式。
对于混合器的命名,应该带有展示性的描述,侧重于表达当应用了这个样式后所带来的视觉效果。比如:"fancy-font"。这与CSS类名有所不同,两者容易混淆。
一种主流的命名方法:CSS类名使用语义化的描述,混合器的名字则采用展示性的描述。
鉴于上面的命名方法,我们得出,混合器的最佳使用点是封装重用的展示性样式。
先看下面例子:
// SASS
.error {
border: 1px red solid;
color: red;
background: #fff;
}
.danger-error {
@extend .error;
color: #fff;
background: red;
font-size: 1.8em;
}
// CSS
.error, .danger-error {
border: 1px red solid;
color: red;
background: #fff;
}
.danger-error {
color: #fff;
background: red;
font-size: 1.8em;
}
SASS 使用 @extend
来实现选择器继承。
它背后的基本原理是,如果 A 继承于 B ,那么在样式表的任何一处 B 都将会被 A,B 这一选择器组替换。
继承是基于选择器的,常常是基于类选择器,上面说到类的命名应当是语义化的,因此,继承也是建立在语义化的关系上。就好比当你在编写样式时发现一个类是另一个类的细化的时候,比如上面.danger-error
是 .error
的细化。
同样的目的我们可以使用混合器来解决,然而混合器的使用会复制大段的代码,并且混合器的命名也会违背上面的原则,对此更好的解决方案是使用继承,上面的例子可以看出,继承只会增加选择器的数量,不会复制大量属性代码。
想要熟练的使用混合器与继承,需要日常反复练习,在实践中体会二者的侧重,这里笔者给出一条经验法则:为效果而混合,为逻辑而继承。
本篇第一节到第六节主要是讲述SASS对于编写样式的拓展,从本节开始我们将从编程语言的角度来认识SASS。就如同其他编程语言一样,
与其他编程语言不一样的是,SASS有处理上的侧重点。我们知道SASS作为一种预编译语言,其最终产物是CSS文件,运行时处理的数据与传统意义上的数据类型有很大的差异。正确认识以及区分不同的数据类型是进行有效编程的基础。
笔者列出几条学习思路供读者参考:
举例:bold、auto、center、“Helvetica Neue”
字符串可以分为有引号与无引号。
无引号的字符串不能以数字和特殊字符开头,不能包括空格和一些特殊字符。
有引号的字符串可以包含除了双引号外的其他字符,一般又将有引号的字符串称为名字,例如举例中的第四项。
字符串最常用的操作符是+
,得出的结果是否包含引号由左边决定。
举例:“foo" + 1 结果为 "foo1"
举例:5px、100%
一个数值包含两个部分:实际数值和单位。
数值可以做四则运算,因此+、-、*、/
是其常用操作符,并且在做四则运算时,单位也会进行运算。
由于在CSS中存在特定值被正斜杠/
分开的情况。为了兼容这种方式,SASS对以下情况进行除法运算。
/
的任意一边使用变量SASS在做除法运算时结果通常是一个小数而不是整数(这通常也是我们想要的结果)。
SASS提供了常用的数学操作函数,以下列出几个极为常用的:
ceil()
,向下取整floor()
,四舍五入取整round()
。这三者经常用于将除法计算结果整数化。percentage()
,接受一个小数参数。comparable($number1,$number2)
判断两个数字(主要是单位)是否能进行比较,unit()
返回单位,unitless()
判断是否有单位。通常在构建函数时对参数进行判断时使用。举例:rgb(171,205,239)
在SASS中,同时使用RGB和HSL来表示颜色,前者是三色光表示法,而后者是色相、饱和度以及亮度。我们通常使用SASS提供的颜色函数来进行操作。当然也可以自定义颜色函数。比起三色光法来说,使用HSL来设计颜色函数更容易达到我们想要的效果。
SASS提供了常用的颜色操作函数,以下列出几个极为常用的:
alpha()
透明度,red(), green(),blue()
通道,hue(),saturation(),lightness()
色度、饱和度、亮度。通常用于函数内部识别参数。adjust()
按给定值调整属性值,scale()
按百分比调整属性值,mix()
按百分比混合颜色。通常用于配色方案。举例:1px solid black
列表是数值的序列,中间用空格或者逗号分隔,列表中可以嵌套列表。
由于分隔符有两种选择,列表嵌套很容易造成不清晰的表述,这里给出一种推荐的写法:在用逗号隔开的列表中加入空格隔开的列表。
另外有一点必须注意,列表必须包含至少一个项目。
SASS提供了常用的颜色操作函数,以下列出几个极为常用的:
nth($list, $n)
,与js数组不一样的是,SASS列表从1开始计数。join($list1, $list2, [$separator])
通常也用来创建新的列表。length()
返回列表的项目数。只有两种:true和false
布尔值的操作符and、or、not
,除此之外还有一些比较运算符会返回布尔值。