@extend用法剖析
提醒:建议继承那些干净的无后代写法的样式
我们经常会遇到这样的情况,当我们在开发页面时候一个class需要包含前一个class的所有样式,但是又必须有他自己特殊新增的样式。但是这两个class其实都是相差无几的,只是有细微的差别。比如错误提示的样式(.error和.specialerror),既然后着只是比前者多一两句样式,为何还要写两个class呢,因为我们不想把前者.error的样式重新在写一遍,无聊极了。但是这样带来一个问题,就是html标签上会多出好几个class。
为了解决这个问题,sass里提供了@extend的解决方法
先看一个例子:
<div class="error specialerror">
Oh no! You've been hacked!
</div>
我们的css如下
.error {
border: 1px #f00;
background-color: #fdd;
}
.specialerror {
border-width: 3px;
}
这里就出现我们刚说的问题了,其实我们心里是十万个不愿意就这么在后面唐突的加个specialerror的,因为如果只写specialerror,就丢失了前面的样式(为什么呢,因为我们没有在specialerror里复写error的样式,只是新增了)
通过Sass的@extend,一个选择器将继承另一个选择器的样式
例如:
.error {
border: 1px #f00;
background-color: #fdd;
}
.specialerror {
@extend .error;
border-width: 3px;
}
被编译为:
.error, .specialerror {
border: 1px #f00;
background-color: #fdd;
}
.specialerror {
border-width: 3px;
}
意味着.error所有的样式都会加到.specialerror上,这样.specialerror就会有.error的样式了。这样我们就可以只写.specialerror了。目前就先这样理解,其实这个@extend实现的方式是跟我们现实逻辑颠倒的。
但是如果改成这样:
.error {
border: 1px #f00;
background-color: #fdd;
}
.specialerror {
@extend .error;
border-width: 3px;
}
.error.intrusion {
background-image: url("/image/hacked.png");
}
加上面这段样式后<div class=”specialerror intrusion”> 就会加上和<div class=”error intrusion”>一样的背景
怎么做到的呢
.error {
border: 1px #f00;
background-color: #fdd;
}
.error.intrusion {
background-image: url("/image/hacked.png");
}
.specialerror {
@extend .error;
border-width: 3px;
}
被编译为:
.error, .specialerror {
border: 1px #f00;
background-color: #fdd; }
.error.intrusion, .specialerror.intrusion {
background-image: url("/image/hacked.png"); }
.specialerror {
border-width: 3px; }
这里需要重点讲解下,其实我们正常理解增加扩充添加就是copy然后paste,是的,这样思考其实也是对的,就像文章一开始那个最简单的例子。但是为了避免不必要的重复。@extend的逻辑稍稍不同。你可以这样认为,使用@extend时候sass会将.error相关样式先拷贝一份,
.specialerror {
@extend .error;
border-width: 3px;
}
然后把字符“specialerror”存储在@extend里,遇到”error“字符就进行替换,这样.specialerror就有了.error的样式啦!这也就能解释,为什么会出现下面.specialerror.intrusion的原因了。
.error.intrusion, .specialerror.intrusion {
background-image: url("/image/hacked.png"); }
当组合选择器的样式时, @extend 能够很聪明得避免不必要的重复,例如.seriousError.seriousError会被转换成.seriousError。不会生成类似#main#footer的不可用选择器。
求证例子:
.hoverlink {
@extend a:hover;
}
a:hover {
text-decoration: underline;
}
被编译为:
a:hover, .hoverlink {
text-decoration: underline; }
就像上面的.error.intrusion ,任何使用 a:hover 都会替换为 .hoverlink,即使中间包含其他选择器。例如:
.hoverlink {
@extend a:hover;
}
.comment a.user:hover {
font-weight: bold;
}
被编译为:
.comment a.user:hover, .comment .user.hoverlink {
font-weight: bold; }
Multiple Extends
一个选择器还可以扩充多个选择器的样式例如:
.error {
border: 1px #f00;
background-color: #fdd;
}
.attention {
font-size: 3em;
background-color: #ff0;
}
.seriousError {
@extend .error;
@extend .attention;
border-width: 3px;
}
被编译为:
.error, .seriousError {
border: 1px #f00;
background-color: #fdd; }
.attention, .seriousError {
font-size: 3em;
background-color: #ff0; }
.seriousError {
border-width: 3px; }
对于下面这种只需注意下就行,就是.criticalError内 “@extend .seriousError”这句话。在运行这句语句时候,sass会检测到.seriousError内有“@extend .error”。
所以.criticalError既有.error的样式也有.seriousError的样式,故criticalError需要替换的是error和seriousError。
.error {
border: 1px #f00;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
.criticalError {
@extend .seriousError;
position: fixed;
top: 10%;
bottom: 10%;
left: 10%;
right: 10%;
}
被编译为:
.error, .seriousError, .criticalError {
border: 1px #f00;
background-color: #fdd; }
.seriousError, .criticalError {
border-width: 3px; }
.criticalError {
position: fixed;
top: 10%;
bottom: 10%;
left: 10%;
right: 10%; }
选择器序列
例如.foo .bar或者 .foo + .bar, 目前还不能被扩展. 但是对于嵌套的选择器还是可以使用@extend添加到其他选择器的 例如:
#fake-links .link {
@extend a;
}
a {
color: blue;
&:hover {
text-decoration: underline;
}
}
编译为:
a, #fake-links .link {
color: blue; }
a:hover, #fake-links .link:hover {
text-decoration: underline; }
当两个没有共同点的序列扩充组合时候, 将会产生两个不同的选择器: 一种是第一个序列在前,另一种是第二个序列在前例如: #admin .tabbar会和#demo .overview调换位置。
#admin .tabbar a {
font-weight: bold;
}
#demo .overview .fakelink {
@extend a;
}
被编译为:
#admin .tabbar a,
#admin .tabbar #demo .overview .fakelink,
#demo .overview #admin .tabbar .fakelink {
font-weight: bold; }
如果另个序列有一些共同的选择器,这些选择器将会被组合在一起而且只有不同的将会保留下来。下面这个例子中, 每个写都包含id #admin, 所以产生的选择器就会合并这两个#admin。#admin .tabbar和 #admin .overview会调换位置,换完之后在省略重复的。
#admin .tabbar a {
font-weight: bold;
}
#admin .overview .fakelink {
@extend a;
}
这被编译为:
#admin .tabbar a,
#admin .tabbar .overview .fakelink,
#admin .overview .tabbar .fakelink {
font-weight: bold; }