前言
前面我們已經(jīng)學(xué)習(xí)了 Scss 的基礎(chǔ)。其實(shí),能夠運(yùn)用之前的技巧已經(jīng)足夠了,在日常開發(fā)中,對 CSS 的熟練使用比對 Scss 的熟練使用更重要。但本文集既然是講學(xué)習(xí) Scss,自然是希望能夠?qū)?Scss 有更深的研究。當(dāng)然,不實(shí)用、復(fù)雜且不易懂的內(nèi)容是被剔除的,畢竟學(xué)習(xí)工具的首要目的還是實(shí)用。
@extend實(shí)現(xiàn)樣式復(fù)用
想必大家在日常的開發(fā)中常常為這種情況苦惱:例如我在寫一個(gè)頁面,頁面里好幾個(gè)地方是相同的樣式,又或者這個(gè)地方的樣式有一部分與另一個(gè)地方的樣式完全重合,這里只是有一點(diǎn)不同而已,但是使用 CSS 并不能實(shí)現(xiàn)代碼的復(fù)用,只能用 CV 大法搬運(yùn)代碼。為了解決這樣的需求和場景,Scss 便實(shí)現(xiàn)了該功能,使用@extend便可以實(shí)現(xiàn)對重復(fù)代碼的復(fù)用。
.error {
border: 1px #f00;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
這里將.error的樣式在seriousError里進(jìn)行復(fù)用,代碼看起來簡潔美觀。當(dāng)然,@extend不僅僅支持類選擇器,也支持偽類選擇器。
.hoverlink {
@extend a:hover;
}
a:hover {
text-decoration: underline;
}
上一篇文章我們提到,Scss 無論再怎么書寫,最終都會(huì)被編譯為 CSS。@extend方法的本質(zhì)其實(shí)就是將.hoverlink添加到a:hover中。不是代碼中表現(xiàn)的那樣,將其他類名下的樣式“拷貝”到當(dāng)前類名下面,而是將當(dāng)前類名添加到其他被 extend 的類名里,成為“組選擇器”。上述代碼編譯為:
a:hover, .hoverlink {
text-decoration: underline; }
但不論如何,這樣的書寫讓動(dòng)輒幾百、幾千行的 CSS 代碼清晰了很多。既然是寫得更少,@extend自然是不止使用一次,在一個(gè)樣式里,可以@extend多個(gè)其他類名下的樣式。
.error {
border: 1px #f00;
background-color: #fdd;
}
.attention {
font-size: 3em;
background-color: #ff0;
}
.seriousError {
@extend .error;
@extend .attention;
border-width: 3px;
}
僅僅如此嗎?如果只是如此,那@extend的能力依然不算強(qiáng)大。既然是復(fù)用,那就貫徹到底。我們可以在一個(gè)類名下@extend另一個(gè)類名的樣式,那這個(gè)類名可以在其他類名下被@extend嗎?答案是肯定的:
.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%;
}
怎么樣?是不是非常強(qiáng)大?這可以讓平時(shí)反復(fù)出現(xiàn)的樣式代碼變得簡潔多了。但代碼量大的情況下依然是需要寫注釋的,類名龐雜的時(shí)候,需要注釋@extend的樣式在第幾行,這對于你返回修改樣式時(shí)非常有用。
@mixin實(shí)現(xiàn)更強(qiáng)大的復(fù)用
@mixin其實(shí)可以理解為函數(shù)(Scss有函數(shù),但本文集不打算涉及,且Scss的函數(shù)并沒有多易用)。@mixin可以理解為聲明語句,例如,聲明一個(gè)混入:
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
large-text 并不是一個(gè)類名,僅僅是一個(gè)“混入”名而已,也可以說是“代碼塊變量”。讓我們回顧下前面講到的知識(shí),是時(shí)候串聯(lián)起來了。& 符在@mixin里也是可用的:
@mixin clearfix {
display: inline-block;
&:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
* html & { height: 1px }
}
“變量”聲明了,哪里使用呢?如何使用呢?其實(shí),在標(biāo)題里我們就說了,@mixin只是更強(qiáng)大的復(fù)用而已,后面我們會(huì)講到其與@extend的區(qū)別。前面講到,@mixin可以理解為函數(shù),函數(shù)聲明了,是不是需要調(diào)用呢?要想使用@mixin,可以在需要復(fù)用樣式的類名下使用@include進(jìn)行引用。不在一個(gè)選擇器下使用這些樣式,光使用@include是會(huì)無效的!
.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
}
同@extend一樣,@mixin內(nèi)部也可以@include其他@mixin的樣式:
@mixin compound {
@include highlighted-background;
@include header-text;
}
講到這里,@mixin依然與@extend一樣,并沒有突顯什么強(qiáng)大的功能。僅僅是樣式的復(fù)用而已,而且比@extend還麻煩。接下來,來看看@mixin與眾不同的地方:參數(shù)。
@mixin sexy-border($color, $width) {
border: {
color: $color;
width: $width;
style: dashed;
}
}
p { @include sexy-border(blue, 1in); }
如同函數(shù)一樣,@mixin可以攜帶參數(shù),在@include使用時(shí)動(dòng)態(tài)傳入,依據(jù)不同的需求做出不同的選擇。因?yàn)槭菂?shù),其實(shí)就是變量,所以必須使用$開頭。與 ES6 中的函數(shù)一樣,@mixin的參數(shù)也支持默認(rèn)值:
@mixin sexy-border($color: blue, $width: 1in) {
border: {
color: $color;
width: $width;
style: dashed;
}
}
不僅如此,@mixin還支持類似于 Vue 插槽一般的功能:
@mixin apply-to-ie6-only {
* html {
@content;
}
}
@include apply-to-ie6-only {
#logo {
background-image: url(/logo.gif);
}
}
上述代碼中,@content起到一個(gè)占位符的作用,與 Vue 中 slot 作為預(yù)留空間的作用一樣,在@include時(shí)可以添加各種樣式,這些樣式會(huì)被添加到@content的位置,最終編譯為 CSS 時(shí)會(huì)被統(tǒng)一編譯到一起。但這里最重要的在于,替換@content的代碼的作用域在原來的位置,@content相當(dāng)于一個(gè)指向該位置的指針而已。也就是說,被傳進(jìn)去代替@content的代碼片段不能使用在@mixin里定義的變量!
* html #logo {
background-image: url(/logo.gif);
}
為了使@mixin與@include更加方便,Scss 增加了這兩者的語法糖,@mixin可以簡寫為 =,@include可以簡寫為+,并且{}可以省略:
=apply-to-ie6-only
* html
@content
+apply-to-ie6-only
#logo
background-image: url(/logo.gif)
@mixin 與 @extend 的區(qū)別與選擇
之前我們講過,@extend的本質(zhì)其實(shí)是將一個(gè)樣式的類名組合在一起形成組選擇器,共用一段樣式代碼,而@mixin則恰恰相反。
@extend
.button {
background: green;
}
.button-1 {
@extend .button;
}
.button-2 {
@extend .button;
}
// 編譯后
.button,
.button-1,
.button-2 {
background: green;
}
@mixin
@mixin button {
background-color: green;
}
.button-1 {
@include button;
}
.button-2 {
@include button;
}
// 編譯后
.button {
background-color: green;
}
.button-1 {
background-color: green;
}
.button-2 {
background-color: green;
}
所以,二者的區(qū)別顯而易見,使用@extend可以減少編譯后代碼量,不過這不重要,編譯后的 CSS 誰會(huì)在乎呢?在一些靜態(tài)的復(fù)用上,@extend更加簡單方便,但@mixin的優(yōu)勢在于可以傳參,使用上更加靈活。
但從實(shí)際來看,@extend更適合局部的復(fù)用,在復(fù)用父級樣式或者兄弟樣式時(shí)很有用,方便易得。使用@mixin可以像 JS 模塊化一樣在代碼頭部就初始化一些樣式“混入”,在樣式書寫過程中如果遇到可以復(fù)用的樣式(特別是需要靈活傳參的樣式),便可以在樣式表頭部聲明,在任意位置復(fù)用。