Scss 初識(shí) @extend 與 @mixin

前言

前面我們已經(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ù)用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容