上一篇詳述了Sass如何嵌套、導(dǎo)入和注釋這3個基本方式來保持條理性和可讀性,這一篇更進(jìn)一步地闡述sass保持樣式復(fù)用和簡潔的方式——混合器和選擇器繼承——這兩種方式都能復(fù)用樣式,使用它們也不難,但一定要注意什么時候該用什么。
零. 混合器——樣式層上復(fù)用
當(dāng)你需要一直復(fù)用大段樣式的時候,可以考慮下混合器。
1. 基本用法
混合器使用@mixin
標(biāo)識符定義,然后通過@include
引入,簡單的說就是用@mixin
定義一個混合器,它具有一個名字和一堆包含在花括號中的規(guī)則,用@include
引入這個混合器(通過混合器的名字),混合器中的樣式規(guī)則就會被提取到調(diào)用@include
的地方。
此外,混合器中也可以包含CSS規(guī)則,可以包含選擇器和選擇器中的規(guī)則,甚至可以用父選擇器標(biāo)識符&
。
@mixin rounded-corners{
-moz-border-radius:5px;
-webkit-border-redius:5px;
border-radius:5px;
}
.notice{
background-color:green;
border:2px solid #0a0;
@include rounded-corners;
}
//導(dǎo)出的css如下
.notice{
background-color:green;
border:2px solid #0a0;
-moz-border-radius:5px;
-webkit-border-redius:5px;
border-radius:5px;
}
2. 可以給混合器傳參
混合器復(fù)用樣式的時候,可以通過傳參改變混合器中的具體屬性值,和function很像。
混合器定義時,參數(shù)名稱必須以變量名形式指定,此外,可選的是,參數(shù)可以有默認(rèn)值,只需要在參數(shù)名后面以冒號:
分隔后寫上默認(rèn)屬性值,如果你了解各類編程語言函數(shù)的默認(rèn)參數(shù)值,這應(yīng)該不會陌生。
引入含有參數(shù)的選擇器時,有兩種傳入?yún)?shù)的形式,一種是僅僅傳入?yún)?shù)值,這要求傳入?yún)?shù)值的順序和混合器定義的參數(shù)順序一致,另一種則是通過$name:value
的形式指定傳入?yún)?shù)的名字和值,這就不要求順序。
以下代碼定義了一個有3個參數(shù)的選擇器來設(shè)置一個鏈接各個狀態(tài)的顏色樣式,其中常規(guī)樣式的顏色$normal
有一個默認(rèn)值#233
,另外兩個參數(shù)沒有默認(rèn)值:
@mixin link-col($hover, $visited, $normal:#233){
color:$normal;
&:hover { color:$hover; }
&:visited { color:$visited; }
}
當(dāng)引入這個混合器的時候,可以有以下兩種方式引入:
//可以這么引入,因?yàn)樽詈笠粋€參數(shù)默認(rèn),可以不傳入
a{
@include link-col(red, gray);
}
//也可以這樣,就不用管順序
a{
@include link-col($visited:gray, $hover:red);
}
3. 混合器的使用場景——注意和類的區(qū)別
如果發(fā)現(xiàn)一直在不停復(fù)用一段樣式,應(yīng)該考慮把這段樣式構(gòu)造成一個混合器,尤其是它本身可能是一組有意義的樣式組合,并且考慮進(jìn)參數(shù)的設(shè)置,讓混合器更加智能。
判斷一組選擇器是否應(yīng)該組合在一起組成一個混合器,一條經(jīng)驗(yàn)法則:能否為這個混合器想出一個能概括它的好名字。如果能想出一個短名字來描述這幾條樣式組合的作用,那么往往能構(gòu)造出一個合適的混合器。
混合器和CSS類很像,css類也可以復(fù)用樣式,一段樣式給一個類,然后那里需要這一段樣式去修飾,就在哪里添加這個類。
區(qū)別在于,類是在HTML中運(yùn)用的,混合器是在樣式表中使用的。這意味著,“類”具有語義化的含義,而混合器僅僅是有關(guān)樣式的,僅僅是描述展示出來是什么樣子的。
能區(qū)分這兩者微妙的區(qū)別,并且有意地去選擇更合適的方式去復(fù)用樣式,這能讓你的代碼保持可讀性和可維護(hù)性。誠然,現(xiàn)在很多流行框架,依舊在用類去復(fù)用樣式,但是語義和樣式的解耦絕對是趨勢。
一. 選擇器繼承——語義化關(guān)系上復(fù)用樣式
剛描述完混合器和類的差別,在于“語義”和“展示樣式”,又突然到了建立在語義化關(guān)系上復(fù)用樣式的選擇器繼承,似乎有點(diǎn)繞,為什么不用類而要用選擇器繼承呢?
實(shí)際上,選擇器繼承最常用的場景就是和類一起工作的。
1. 基本用法
選擇器繼承,用@extend
去繼承一個選擇器定義的所有樣式。以下代碼,.seriousError
將會繼承.error
定義的所有樣式。
.error{
border: 1px red;
background-color: #fdd;
}
.seriousError{
@extend .error;
border-width: 3px;
}
//輸出的CSS代碼是這樣的
.error, .seriousError{
border: 1px red;
background-color: #fdd;
}
.seriousError{
border-width: 3px;
}
是的,平時我們完全可以寫輸出的純CSS代碼,多寫一個選擇器名字和多寫一行@extend
命令,我們覺得差不多。
但是,在上面的例子中,.seriousError
不僅會繼承.error
自身的所有樣式(就像上面的那樣),任何和.error
有關(guān)的組合選擇器樣式也會被.seriousError
以組合選擇器的形式繼承。
比如,在上面的樣式代碼是這樣的:
.error{
border: 1px red;
background-color: #fdd;
}
.seriousError{
@extend .error;
border-width: 3px;
}
.error a{
color:red;
font-weight:bold;
}
h1.error{
font-size:1.3em;
}
//輸出的CSS是這樣的,注意看下面的選擇器
.error, .seriousError{
border: 1px red;
background-color: #fdd;
}
.seriousError{
border-width: 3px;
}
.error a, .seriousError a{
color:red;
font-weight:bold;
}
h1.error, h1.seriousError{
font-size:1.3em;
}
這個時候,如果我們不借助Sass的選擇器繼承,而用純CSS來寫,是不是就會有一些繁瑣了。
我們再來想一下這幾段代碼的含義:我們描述了一個.error
類來整體修飾錯誤提示都應(yīng)該有的樣式,然后.seriousError
是.error
類的細(xì)化,描述了一個嚴(yán)重的錯誤應(yīng)該有的進(jìn)一步的樣式。所以.seriousError
應(yīng)該有.error
相關(guān)的所有樣式,而這就是選擇器繼承幫助我們做的事。
2. 繼承背后的基本實(shí)現(xiàn)思路
@extend
背后最基本的想法是,如果.seriousError
繼承了.error
,那么樣式表中的任何一處.error
選擇器都會用.error, .seriousError
這一選擇器組進(jìn)行替換和打開。
3. 繼承的使用場景
繼承是建立在語義化的關(guān)系上的,當(dāng)一個元素?fù)碛械念惐砻魉菍儆诹硪粋€類時(是另一個類的細(xì)化時),在這種情況下需要復(fù)用樣式時使用,它的本質(zhì)作用還是樣式復(fù)用。
它和混合器相比,繼承生成的代碼量會相對較少,因?yàn)槔^承僅僅重復(fù)選擇器,而混合器是重復(fù)一段樣式。
另外,可以看到,一般它和類一起協(xié)同工作,當(dāng)你在構(gòu)建一些有關(guān)系的類時,在寫這些具有層級關(guān)系的類的樣式的時候,選擇器繼承可以幫你嚴(yán)謹(jǐn)?shù)赝瓿赡承邮降膹?fù)用,無論是這個選擇器本身,還是隱藏在其他復(fù)雜選擇器中的目標(biāo)選擇器。
4. 繼承的高級用法
既然這被稱為選擇器繼承,不是“類”繼承,那么必然繼承是可以針對類之外的選擇器使用的,只是繼承類是最常用的使用場景。
還有一種場景是,繼承一個HTML元素的樣式,如定一個.disabled
類,樣式修飾讓它看上去像一個灰掉的鏈接,通過繼承a這一元素實(shí)現(xiàn):
.disabled{
color: gray;
@extend a;
}
還有一些關(guān)于復(fù)雜選擇器的繼承規(guī)則:
- 如果繼承了一個復(fù)雜的選擇器,那么只會繼承這個復(fù)雜選擇器命中的樣式, 比如
.seriousError @extend .important.error
,那么被繼承的.important.error
被看做一個整體,單獨(dú)的.important
或者.error
是不會被繼承的; - 如果一個選擇器序列繼承了另一個選擇器,那么只會完全命中序列選擇器的才會繼承,比如
(#main .seriousError) @extend .error
(最好不要這么做),那么前者的#main .seriousError
也被看做一個整體,只有完全命中這個選擇器的才會繼承; - 以逗號分隔的選擇器序列是不能被繼承的,因?yàn)檫@和繼承其中任何一個選擇器效果一樣。
5. 使用繼承時注意后代選擇器
可以放心地繼承有后代選擇器修飾的選擇器,但不用用后代選擇器去繼承別的選擇器。即放心地用.serious { @extend (.main .error) }
,但是不要用.something .serious { @exten .error }
。
為什么,因?yàn)椴贿@么做可能會導(dǎo)致繼承迅速變復(fù)雜,sass可能會遺漏一些情況,考慮:
.foo .bar { @extend .baz; }
.bip .baz { a:b; }
當(dāng)下面那條規(guī)則應(yīng)用到.foo .bar
時,有3種情況:
<div class="foo">
<div class="bip">
<div class="bar">...</div>
</div>
</div>
<div class="bip">
<div class="foo">
<div class="bar">...</div>
</div>
</div>
<div class="bip foo">
<div class="bar">...</div>
</div>
所以sass必須要生成3種組合選擇器才能覆蓋這3種情況,但遺憾的是,sass并不總是會生成所有情況,另外,這樣做,選擇器的個數(shù)會迅速增加,所以最好的方式是不要這么用。
三. 小結(jié)
Sass保持樣式復(fù)用和簡潔的兩個方式,一是混合器,混合器主要用于樣式展示層的復(fù)用,可以給混合器傳參從而在復(fù)用代碼的同時保持靈活性,二是選擇器繼承,一般和類一起使用,主要用于建立在語義化關(guān)系上的樣式復(fù)用,注意繼承可能引發(fā)的問題。