2015年10月20日
1.嵌套
Sass 中还提供了选择器嵌套功能,但这也并不意味着你在 Sass 中的嵌套是无节制的,因为你嵌套的层级越深,编译出来的 CSS 代码的选择器层级将越深,这往往是大家不愿意看到的一点。这个特性现在正被众多开发者滥用。
Sass的嵌套分为3种:
a.选择器嵌套
b.属性嵌套
c.伪类嵌套
1、选择器嵌套
假设我们有一段这样的结构:
<header>
<nav>
<a href=“##”>Home</a>
<a href=“##”>About</a>
<a href=“##”>Blog</a>
</nav>
<header>
想选中header中的a标签,在写CSS会这样写:
nav a {
color:red;
}
header nav a {
color:green;
}
那么在Sass中,就可以使用选择器的嵌套来实现:
nav {
a {
color: red;
header & {
color:green;
}
}
}
2.属性嵌套
Sass中还提供属性嵌套,CSS有一些属性前缀相同,只是后缀不一样,比如:border-top/border-right,与这个类似的还有margin、padding、font等属性。假设你的样式中用到了:
.box{
border-top: 1px solid red;
border-bottom: 1px soid green;
}
在Sass中可以这样写:
.box{
border:{
top: 1px solid red;
bottom: 1px solid green;
}
}
3.伪类嵌套
其实伪类嵌套和属性嵌套非常相似,只不过他需要借助'&'符号一起配合使用。我们就拿经典的"clearfix"为例吧:
.clearfix{
&: bofore,
&:after{
content:"";
display: table;
}
&:after{
clear: both;
overflow: hidden;
}
}
编译出来的CSS:
.clearfix:before, .clearfix:after{
content: "";
display: table;
}
.clearfix:after{
clear:both;
overflow: hidden;
}
尽量避免选择器选择器嵌套
混合宏
如果你的整个网站中有几处小样式类似,比如颜色,字体等,在Sass可以使用变量来统一处理,那么这种选择还是不错的。但当你的样式变得越来越复杂,需要重复使用大段的样式时,使用变量就无法达到我们的目的了。这个时候Sass中的混合宏就会变得非常有意义。
1.声明混合宏
不带参数的混合宏:
在Sass中,使用"@mixin"来声明一个混合宏,如:
@mixin border-radius{
-webkit-border-radius: 5px;
border-radius: 5px;
}
其中@mixin是用来声明混合宏的关键词,有点类似CSS中的@media、@font-face一样。border-radius是混合宏的名称。大括号里面是复用的样式代码。
带参数的混合宏:
除了一个不带参数的混合宏之外,还可以在定义混合宏时带有参数,如:
@mixin border-radius($radius:5px){
-webkit-border-radius: $radius;
border-radius: $radius;
}
复杂的混合宏:
上面是一个简单的定义混合宏的方法,当然,Sass中的混合宏还提供更为复杂的,你可以在大括号里面写上带有逻辑关系,帮助更好的做你想做的事,如:
@mixin box-shadow($shadow...){
@if length($shadow) >=1{
@include prefixer(box-shadow, $shadow);
} @else{
$shadow: 0 0 4px rgba(0, 0, 0, .3);
@include prefixer(box-shadow, $shadow);
}
}
这个 box-shadow 的混合宏,带有多个参数,这个时候可以使用“ … ”来替代。简单的解释一下,当 $shadow 的参数数量值大于或等于“ 1 ”时,表示有多个阴影值,反之调用默认的参数值“ 0 0 4px rgba(0,0,0,.3) ”。
2.调用混合宏
在Sass中通过@mixin关键词声明了一个混合宏,那么在实际调用中,其匹配了一个关键词"@include"来调用声明好的混合宏。例如在你的样式中定义了一个圆角的混合宏"border-radius":
@mixin border-radius{
-webkit-border-radius: 3px;
border-radius: 3px;
}
在一个按钮中要调用定义好的混合宏"border-radius", 可以这样使用:
button{
@include border-radius;
}
这个时候编译出来的CSS:
button{
-webkit-border-radius: 3px;
border-radius: 3px;
}
3.混合宏的参数
Sass的混合宏有一个强大的功能,可以传参,那么在Sass中传参主要有一下几种情况:
A)传一个不带值的参数
在混合宏中,可以传一个不带任何值的参数,比如:
@mixin border-radius($radius){
-weblit-border-radius: $radius;
border-radius: $radius;
}
在混合宏“border-radius”中定义了一个不带任何值的参数“$radius”。
在调用的时候可以给这个混合宏传一个参数值:
.box{
@include border-radius(3px);
}
这里表示给混合宏传递了一个"border-radius"的值为"3px"。
编译出来的CSS:
.box{
-webkit-border-radius: 3px;
border-radius: 3px;
}
B)传一个带值的参数
在Sass的混合宏中,还可以给混合宏的参数传一个默认值,例如:
@mixin border-radius($radius:3px){
-webkit-border-radius: $radius;
border-radius: $radius;
}
在混合宏“border-radius”传了一个参数“$radius”,而且给这个参数赋予了一个默认值“3px”。
在调用类似这样的混合宏时,会多有一个机会,假设你的页面中的圆角很多地方都是“3px”的圆角,那么这个时候只需要调用默认的混合宏“border-radius”:
.btn { @include border-radius;}
编译出来的CSS:
.btn{
-webkit-border-radius: 3px;
border-radius: 3px;
}
但有的时候,页面中有些元素的圆角值不一样,那么可以随机给混合宏传值,如:
.box { @include border-radius(50%);}
编译出来的CSS:
.box { -webkit-border-radius: 50%; border-radius: 50%;}
C)传多个参数
Sass混合宏除了能传一个参数之外,还可以传多个参数,如:
@mixin center($width, $height){
width: $width;
height: $height;
position: absolute;
top: 50%;
left: 50%;
margin-top: -($height)/2;
margin-left: -($width)/2;
}
在混合宏"center"就传了多个参数。在实际调用和其调用其他混合宏是一样的:
.box-center{
@include center(500px, 300px);
}
编译出来的CSS:
.box-center{
width: 500px;
height: 300px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -150px;
margin-left: -250px;
}
有一个特别的参数"..."。当混合宏传的参数过多之时,可以使用参数来替代,如:
@mixin box-shadow($shadows...){
@if length($shadows) >= 1{
-webkit-box-shadow: $shadows;
box-shadow: $shadows;
}@else{
$shadows: 0 0 2px rgba(#000, .25);
-webkit-box-shadow: $shadows;
box-shadow: $shadows;
}
}
在实际调用中:
.box{
@include box-shadow(0 0 1px rgba(#000, .5), 0 0 2px rgba(#000, .2));
}
编译出来的CSS:
.box{
-webkit-box-shadow: 0 0 1px rgba(0, 0, 0 , 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 1px rgba(0, 0, 0 , 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
}
D)混合宏的不足
混合宏在实际编码中给我们带来很多方便之处,特别是对于复用重复代码块。但其最大的不足之处是会生成冗余的代码块。比如在不同的地方调用一个相同的混合宏时。如:
@mixin border-radius{
-webkit-border-radius: 3px;
border-radius: 3px;
}
.box{
@include border-radius;
margin-bottom: 5px;
}
.btn{
@include border-radius;
}
示例在".box"和".btn"中都调用了定义好的"border-radius"混合宏。先来看编译出来的CSS:
.box{
-webkit-border-radius: 3px;
border-radius: 3px;
margin-bottom: 5px;
}
.btn{
-webkit-border-radius: 3px;
border-radius: 3px;
}
上例明显可以看出,Sass在调用相同的混合宏时,并不能智能的将相同的样式代码块合并在一起。这也是Sass的混合宏最不足之处。
扩展/继承
在Sass中通过关键词"@extend"来继承已存在的类样式块,从而实现代码的继承。如下所示:
//SCSS
.btn{
border:1px solid #ccc;
padding: 6px 10px;
font-size: 14px;
}
.btn-primary{
background-color: #f36;
color: #fff;
@extend .btn;
}
.btn-second{
background-color: orange;
color: #fff;
@extend .btn;
}
编译出来之后:
//CSS
.btn, .btn-primary, .btn-second{
border: 1px solid #ccc;
padding: 6px 10px;
font-size: 14px;
}
.btn-primary{
background-color: #f36;
color: #fff;
}
.btn-second{
background-color: orange;
color: #fff;
}
从示例代码可以看出,在Sass中的继承,可以继承类样式块中所有样式代码,而且编译出来的CSS会将选择器合并在一起,形成组合选择器:
.btn, .btn-primary, .btn-second{
border: 1px solid #ccc;
padding: 6px 10px;
font-size: 14px;
}
占位符%placeholder
Sass中的占位符%placeholder功能是一个很强大、很实用的一个功能,他可以取代以前CSS中的基类造成的代码冗余的情形。因为%placeholder声明的代码,如果不被@extend调用的话,不会产生任何代码。示例:
%mt5{
margin-top: 5px;
}
%pt5{
padding-top: 5px;
}
这段代码没有被@extend调用,他并没有产生任何代码块,只是静静的躺在你的某个SCSS文件中。只有通过@extend调用才会产生代码:
//SCSS
%mt5{
margin-top: 5px;
}
%pt5{
padding-top: 5px;
}
.btn{
@extend %mt5;
@extend %pt5;
}
.block{
@extend %mt5;
span{
@expend %pt5;
}
}
编译出来的CSS
//CSS
.btn, .block{
margin-top: 5px;
}
.btn, .block span{
padding-top: 5px;
}
从编译出来的CSS代码可以看出,通过@expend调用的占位符,编译出来的代码会将相同的代码合并在一起。这也是我们希望看到的效果,也让你的代码变的更为干净。
混合宏 VS 继承 VS 占位符
a)混合宏的使用
如果你的代码块中涉及到变量,建议使用混合宏来创建相同的代码块。
b)Sass 继承
如果你的代码块不需要传任何变量参数,而且有一个基类已在文件中存在,那么建议使用Sass继承
c)占位符
编译出来的 CSS 代码和使用继承基本上是相同,只是不会在代码中生成占位符 mt 的选择器。那么占位符和继承的主要区别的,“占位符是独立定义,不调用的时候是不会在 CSS 中产生任何代码;继承是首先有一个基类存在,不管调用与不调用,基类的样式都将会出现在编译出来的 CSS 代码中。”
插值#{}
使用CSS预处理器语言的一个主要原因是想使用Sass获得一个更好的结构体系。比如说你想写更干净的、高效的和面向对象的CSS。Sass中的插值就是重要的一部分。示例:
$properties: (margin, padding);
@mixin set-value($side, $value){
@each $prop in $properties{
#{$prop}-#{side}: $value;
}
}
.login-box{
@include set-value(top, 14px);
]
它可以让变量和属性工作的很完美,上面的代码编译成CSS:
.login-box{
margin-top: 14px;
padding-top: 14px;
}
这是Sass插值中的一个简单的实例。当你想设置属性值的时候你可以使用字符串插入进来。另一个有用的用法是构建一个选择器。可以这样使用:
@mixin generate-sizes($class, $small, $medium, $big){
.#{$class}-small {font-size: $small;}
.#{$class}-medium{font-size: $medium;}
.#{$class}-big{font-size: $big;}
}
@include generate-sizes("header-text", 12px, 20px, 40px);
编译出来的CSS:
.header-text-small {font-size:12px;}
.header-text-medium {font-size:20px;}
.header-text-big{font-size: 40px;}
$margin-big: 40px;
$margin-medium: 20px;
$margin-small: 12px;
@mixin set-value($size){
margin-top: $margin-#{$size};
}
.login-box{
@include set-value(big);
}
上面的Sass代码编译出来,你会得到下面的信息:
error style.scss (Line 5: Undefined variable: “$margin-".)
所以,#{}语法并不是随处可用,你也不能在mixin中调用:
@mixin updated-status {
margin-top: 20px;
background: #F00;
}
$flag: "status";
.navigation {
@include updated-#{$flag};
}
上面的代码在编译成 CSS 时同样会报错:
error style.scss (Line 7: Invalid CSS after "...nclude updated-": expected "}", was "#{$flag};")
幸运的是,可以使用 @extend 中使用插值。例如:
%updated-status {
margin-top: 20px;
background: #F00;
}
.selected-status {
font-weight: bold;
}
$flag: "status";
.navigation {
@extend %updated-#{$flag};
@extend .selected-#{$flag};
}
上面的 Sass 代码是可以运行的,因为他给了我们力量,可以动态的插入 .class 和 %placeholder。当然他们不能接受像 mixin 这样的参数,上面的代码编译出来的 CSS:
.navigation {
margin-top: 20px;
background: #F00;
}
.selected-status, .navigation {
font-weight: bold;
}
在 Sass 的社区正在积极讨论插值的局限性,谁又知道呢,也许我们很快将能够使用这些技术也说不定呢。
注释
Sass有两种注释方式,暂且将其命名为:
1.块注释"/*......... */"
2.行注释 "//"
两者区别,前者会在编译出来的CSS显示,后者在编译出来的CSS中不会显示,示例:
//定义一个占位符
%mt5{
margin-top: 5px;
}
/*调用一个占位符*/
.box{
@extend %mt5;
}
编译出来的CSS
.box{
margin-top: 5px;
}
/*调用一个占位符*/