前面我们已经知道sass中的变量了,但是变量能记录的毕竟只是一个值,顶多把一个属性的所有值全部记录进去,比如这样:
$primary-border:1px solid #899;
.box{
border:$primary-border;
}
这样固然可以让box这个选择器很轻松地获得一个边框样式,但是如果我有大量公用的样式呢?比如文字颜色,字体大小这些东西其实都可以统一起来,那这时候如果我们再一条一条的去存变量,然后再去使用的话就不太方便了。混合(Mixin)就是用来解决这个问题的,它可以把一整段代码打包,然后像一个变量一样在其他地方使用。
混合在官方的解释是这样的:混合指令(Mixin)用于定义可重复使用的样式,避免了使用无语意的 class。混合指令可以包含所有的 CSS 规则,绝大部分 Sass 规则,甚至通过参数功能引入变量,输出多样化的样式。
来看案例:
考虑图中按钮的实现,咱先用以前的方法来写:
$btnHeight: 40px;
$grayBorder: 1px solid #bbb;
$blueBorder: 1px solid #4395ff;
.btnGray{
height: $btnHeight;
border: $grayBorder;
padding: 20px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
}
.btnBlue{
height: $btnHeight;
border: $blueBorder;
padding: 10px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
}
可以看到,以上代码中虽然我们大量用了变量,但是两个选择器里面内容的相似度依然非常高,大家可能在想,明明border-radius、font、text-align都可以用变量来定义,但是仔细想想,这样的代码真的是我们需要的么? 稍微复杂点就全都是变量? 这恐怕会越写越乱吧!所以面对这样的代码,我们就需要用到混合了
混合
现在我们来看看用混合怎么写:
@mixin btn{
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
}
.btnGray{
@include btn;
border:1px solid #bbb;
padding: 20px;
}
.btnBlue{
@include btn;
border:1px solid #4395ff;
padding: 10px;
}
编译之后:
.btnGray {
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
border: 1px solid #bbb;
padding: 20px;
}
.btnBlue {
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
border: 1px solid #4395ff;
padding: 10px;
}
可以看到这代码一下就变得很清晰了。我们来看看这段代码里发生了什么事情:
第一段,利用@mixin指令创建了一个“超级变量”:btn,而这个“超级变量”是一个集合,集合里面可以写所有的css规则。然后通过@include指令引用这个“超级变量”。这样我们就做到了把几个相似选择器中重复的代码提取出来,达到了代码的高复用性。而sass把这个定义“超级变量”, 和引用“超级变量”叫做混合。
当然在这之前我们可能会考虑写一个公用的class,然后在需要的地方去引入这个class就可以了,但是那样的代码毕竟可维护性不高,性能也是肯定不如sass的,而且sass的混合还有更加强大的地方,往下看。
混合中的参数
在上面这段代码中,虽然我已经把重复的代码全部都提取出去了,但是剩下的两个属性:border和padding两个选择器之间的差别也不太大,那有没有可能把这两个属性也提取出来呢?是可以的:
@mixin btn($color){
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
border:1px solid $color;
}
.btnGray{
@include btn(#899);
padding: 20px;
}
.btnBlue{
@include btn(#4395ff);
padding: 10px;
}
编译过后:
.btnGray {
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
border: 1px solid #899;
padding: 20px;
}
.btnBlue {
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
border: 1px solid #4395ff;
padding: 10px;
}
可以看到这段代码里,编译过后的代码和之前的代码是一样的,但是sass代码又更加精简一些了 ———— 在定义混合样式 btn 的时候,在后面加上了一个括号,括号里其实就是一个变量名称,但是这个变量并没有值。然后可以看到这个变量在下面用到了 : border: 1px solid $color; 在这里用到了这个变量。
那么也就代表了,在这个混合样式没有被调用的时候,这个border里面的$color是得不到值的,只有当调用这个混合样式的时候,给它传入一个值,这时候border才能得到传入进来的值,然后把传入进来的值替换到border这条样式上去,然后在把自己作为一个整体替换到引入混合样式的地方。这个过程看起来可能会有点复杂,这么说:
我们把这整个过程当做是去存物处取东西,不同的客户拿着不同的钥匙来,那么取走的东西肯定也是不一样的,但是存物处突然搞活动了,所有客户来取东西,都送一盒鸡蛋!那么这时候我们整个过程就比较好理解了,不同的客户(.btnGray、.btnBlue)拿着不同的钥匙(#899、#4395ff)来btn这个存物处这里取东西,那么btn会根据不同的钥匙取出不同的东西(.btnGray得到的是:border: 1px solid #899, 而.btnBlue得到的是:border: 1px solid #4395ff)。然后附赠一盒鸡蛋(公共样式) 最后,.btnGray和.btnBlue都得到了公共样式,并且分别得到了颜色不一样的边框样式~
1. @mixin btn($color){
2. height: 40px;
3. border-radius: 4px;
4. font: 24px/40px '微软雅黑';
5. text-align: center;
6. border:1px solid $color;
7. }
8.
9. .btnGray{
10. @include btn(#899);
11. padding: 20px;
12. }
13.
14. .btnBlue{
15. @include btn(#4395ff);
16. padding: 10px;
17. }
再来看这段代码,从上到下解析,从1~7行一开始是不解析的,因为在这期间它作为一个混合样式还没有被调用。所以不会解析
到第10行的时候看到了一个 @include指令,并且后面跟着的名称是 btn .那这时候sass会去找有没有名字叫做btn的混合样式,哎,貌似刚才经过的地方有这么个家伙,感觉有点眼熟,然后立马把1~7行的btn抓过来了:这里要调用你了! 再往后一看,哎哟,居然还需要钥匙,恰好第10行代码 btn的后面的括号里就有一个钥匙,于是乎1~7行在这一瞬间就被替换成了这样:
@mixin btn{
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
border:1px solid #899;
}
然后再把这一段代码复制到第10行这个地方,于是选择器.btnGray就获得了完整的代码。替换完成了之后 1~7行就立刻又恢复原样了。代码继续往下走,走到第15行的时候,哎,这个地方还需要那哥们,于是btn又被拎过来了... 重复刚才的动作。
要注意的点:定义了参数的混合样式,必须传入参数,否则会报错
多个参数
到这里,混合这个东西似乎就比较清楚了。不过细心的同学可能发现了,貌似两个选择器里的padding也可以这样操作呀?
@mixin btn($color,$pad){
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
border:1px solid $color;
padding: $pad;
}
.btnGray{
@include btn(#899,20px);
}
.btnBlue{
@include btn(#4395ff,10px);
}
是的,混合样式后面的的变量其实叫做参数,参数用于给混合指令中的样式设定变量,并且赋值使用。在定义混合指令的时候,按照变量的格式,通过逗号分隔,将参数写进圆括号里。引用指令时,按照参数的顺序,再将所赋的值对应写进括号
要注意的点:多个参数在调用传值时,只能按照定义的顺序传入,中间不可缺少参数 如果想要打乱顺序,则可以这样写:
.btnGray{
@include btn($pad: 20px, $color: #899);
}
参数默认值
甚至混合指令也可以使用给变量赋值的方法给参数设定默认值,然后,当这个指令被引用的时候,如果没有给参数赋值,则自动使用默认值:
@mixin btn($color: #899, $pad: 20px){
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
border:1px solid $color;
padding: $pad;
}
这样的话变量$color 和 $pad 就拥有默认值了,在调用的时候,如果没有传入值,那么这两个变量将会得到这里定义的默认值
.btnGray{
@include btn;
}
编译之后:
.btnGray {
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
border: 1px solid #899;
padding: 20px;
}
要注意的点:如果定义了多个变量,当只想改变其中一个变量时,可以指定变量名,比如现在我们的混合样式已经带有默认值了,现在我需要让.btnGray的padding值变成10px 要怎么办呢?
如果我们这样写:
.btnGray{
@include btn(10px);
}
编译之后:
.btnGray {
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
border: 1px solid 10px; /*传入的第一个参数默认会放在这个位置*/
padding: 20px;
}
这样无疑是错误的,所以我们可以指定其变量名:
.btnGray{
@include btn($pad: 10px);
}
编译之后:
.btnGray {
height: 40px;
border-radius: 4px;
font: 24px/40px '微软雅黑';
text-align: center;
border: 1px solid #899; /*这时候这里会使用默认值*/
padding: 10px; /*指定变量替换这里的值*/
}
一些小技巧
1.在混合样式里,可以引入其他混合样式:
@mixin compound {
@include highlighted-background;
@include header-text;
}
@mixin highlighted-background { background-color: #fc0; }
@mixin header-text { font-size: 20px; }
.box{
@include compound;
}
编译之后:
.box{
background-color: #fc0;
font-size: 20px;
}
2.可以把整个选择器当做混合样式的一部分,这在代码模块化的时候非常有用:
@mixin silly-links {
a {
color: blue;
background-color: red;
}
}
.box{
@include silly-links;
}
编译成:
.box a {
color: blue;
background-color: red;
}
3.当不确定参数个数的时候,可以这样写:
@mixin box-shadow($shadows...) {
-moz-box-shadow: $shadows;
-webkit-box-shadow: $shadows;
box-shadow: $shadows;
}
.shadows {
@include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
}