1. 程式人生 > 實用技巧 >Sass簡單、快速上手_Sass快速入門學習筆記總結

Sass簡單、快速上手_Sass快速入門學習筆記總結

Sass是世界上最成熟、穩定和強大的專業級css擴充套件語言,除了Sass是css的一種前處理器語言,類似的語言還有Less,Stylus等。 這篇文章關於Sass快速入門學習筆記。

資源網站大全 https://55wd.com

1. 使用變數;

Sass讓人們受益的一個重要特性就是它為css引入了變數。你可以把反覆使用的css屬性值 定義成變數,然後通過變數名來引用它們,而無需重複書寫這一屬性值。或者,對於僅使用過一 次的屬性值,你可以賦予其一個易懂的變數名,讓人一眼就知道這個屬性值的用途。

sass使用$符號來標識變數(老版本的sass使用!來標識變數。改成$是多半因為!highlight-color看起來太醜了。)

,比如$highlight-color和$sidebar-width。為什麼選擇$符號呢?因為它好認、更具美感,且在css中並無他用,不會導致與現存或未來的css語法衝突。

1-1. 變數宣告;

sass變數的宣告和css屬性的宣告很像:

$highlight-color: #F90;

這意味著變數$highlight-color現在的值是#F90。任何可以用作css屬性值的賦值都 可以用作sass的變數值,甚至是以空格分割的多個屬性值,如$basic-border: 1px solid black;,或以逗號分割的多個屬性值,如$plain-font: "Myriad Pro"、Myriad、"Helvetica Neue"、Helvetica、"Liberation Sans"、Arial和sans-serif; sans-serif;。這時變 量還沒有生效,除非你引用這個變數——我們很快就會了解如何引用。

與css屬性不同,變數可以在css規則塊定義之外存在。當變數定義在css規則塊內,那麼該變數只能在此規則塊內使用。如果它們出現在任何形式的{...}塊中(如@media或者@font-face塊),情況也是如此:

$nav-color: #F90;
nav {
  $width: 100px;
  width: $width;
  color: $nav-color;
}

//編譯後

nav {
  width: 100px;
  color: #F90;
}

在這段程式碼中,$nav-color這個變數定義在了規則塊外邊,所以在這個樣式表中都可以像nav規則塊那樣引用它。$width這個變數定義在了nav的{ }規則塊內,所以它只能在nav規則塊 內使用。這意味著是你可以在樣式表的其他地方定義和使用$width變數,不會對這裡造成影響。

只宣告變數其實沒啥用處,我們最終的目的還是使用它們。上例已介紹瞭如何使用$nav-color和$width這兩個變數,接下來我們將進一步探討變數的使用方法。

1-2. 變數引用;

凡是css屬性的標準值(比如說1px或者bold)可存在的地方,變數就可以使用。css生成時,變數會被它們的值所替代。之後,如果你需要一個不同的值,只需要改變這個變數的值,則所有引用此變數的地方生成的值都會隨之改變。

$highlight-color: #F90;
.selected {
  border: 1px solid $highlight-color;
}

//編譯後

.selected {
  border: 1px solid #F90;
}

看上邊示例中的$highlight-color變數,它被直接賦值給border屬性,當這段程式碼被編譯輸出css時,$highlight-color會被#F90這一顏色值所替代。產生的效果就是給selected這個類一條1畫素寬、實心且顏色值為#F90的邊框。

在宣告變數時,變數值也可以引用其他變數。當你通過粒度區分,為不同的值取不同名字時,這相當有用。下例在獨立的顏色值粒度上定義了一個變數,且在另一個更復雜的邊框值粒度上也定義了一個變數:

$highlight-color: #F90;
$highlight-border: 1px solid $highlight-color;
.selected {
  border: $highlight-border;
}

//編譯後

.selected {
  border: 1px solid #F90;
}

這裡,$highlight-border變數的宣告中使用了$highlight-color這個變數。產生的效 果就跟你直接為border屬性設定了一個1px$highlight-color solid的值是一樣的。 最後,我們來了解一下變數命名的實用技巧,以結束關於變數的介紹。

1-3. 變數名用中劃線還是下劃線分隔;

sass的變數名可以與css中的屬性名和選擇器名稱相同,包括中劃線和下劃線。這完全取決於個人的喜好,有些人喜歡使用中劃線來分隔變數中的多個詞(如$highlight-color),而有些人喜歡使用下劃線(如$highlight_color)。使用中劃線的方式更為普遍,這也是compass和本文都用的方式。

不過,sass並不想強迫任何人一定使用中劃線或下劃線,所以這兩種用法相互相容。用中劃線宣告的變數可以使用下劃線的方式引用,反之亦然。這意味著即使compass選擇用中劃線的命名方式,這並不影響你在使用compass的樣式中用下劃線的命名方式進行引用:

$link-color: blue;
a {
  color: $link_color;
}

//編譯後

a {
  color: blue;
}

在上例中,$link-color和$link_color其實指向的是同一個變數。實際上,在sass的大 多數地方,中劃線命名的內容和下劃線命名的內容是互通的,除了變數,也包括對混合器和Sass函式的命名。但是在sass中純css部分不互通,比如類名、ID或屬性名。

儘管變數自身提供了很多有用的地方,但是sass基於變數提供的更為強大的工具才是我們關注的焦點。只有當變數與sass的其他特性一起使用時,才能發揮其全部的潛能。接下來,我們將探討其中一個非常重要的特性,即規則巢狀。

2. 巢狀CSS 規則;

css中重複寫選擇器是非常惱人的。如果要寫一大串指向頁面中同一塊的樣式時,往往需要 一遍又一遍地寫同一個ID:

#content article h1 { color: #333 }
#content article p { margin-bottom: 1.4em }
#content aside { background-color: #EEE }

像這種情況,sass可以讓你只寫一遍,且使樣式可讀性更高。在Sass中,你可以像俄羅斯套娃那樣在規則塊中巢狀規則塊。sass在輸出css時會幫你把這些巢狀規則處理好,避免你的重複書寫。

 /* 編譯前*/
#content {
  article {
    h1 { color: #333 }
    p { margin-bottom: 1.4em }
  }
  aside { background-color: #EEE }
}

 /* 編譯後 */
#content article h1 { 
    color: #333 
}
#content article p {
     margin-bottom: 1.4em 
}
#content aside {
     background-color: #EEE 
}

上邊的例子,會在輸出css時把它轉換成跟你之前看到的一樣的效果。這個過程中,sass用了兩步,每一步都是像開啟俄羅斯套娃那樣把裡邊的巢狀規則塊一個個開啟。首先,把#content(父級)這個id放到article選擇器(子級)和aside選擇器(子級)的前邊:

 /* 編譯前 */
#content {
  article {
    h1 { color: #333 }
    p { margin-bottom: 1.4em }
  }
  #content aside {  color: rgb(136, 0, 0);">/* 編譯後 */
#content article h1 { 
  color: #333
} #content article p {
  margin-bottom: 1.4em
} #content aside {
  ">}

然後,#content article裡邊還有巢狀的規則,sass重複一遍上邊的步驟,把新的選擇器新增到內嵌的選擇器前邊。

一個給定的規則塊,既可以像普通的CSS那樣包含屬性,又可以巢狀其他規則塊。當你同時要為一個容器元素及其子元素編寫特定樣式時,這種能力就非常有用了。

#content {
  background-color: #f5f5f5;
  aside { background-color: #eee }
}

容器元素的樣式規則會被單獨抽離出來,而巢狀元素的樣式規則會像容器元素沒有包含任何屬性時那樣被抽離出來。

#content { background-color: #f5f5f5 }
#content aside { background-color: #eee }

大多數情況下這種簡單的巢狀都沒問題,但是有些場景下不行,比如你想要在巢狀的選擇器 裡邊立刻應用一個類似於:hover的偽類。為了解決這種以及其他情況,sass提供了一個特殊結 構&。

2-1. 父選擇器的識別符號&;

一般情況下,sass在解開一個巢狀規則時就會把父選擇器(#content)通過一個空格連線到子選擇器的前邊(article和aside)形成(#content article和#content aside)。這種在CSS裡邊被稱為後代選擇器,因為它選擇ID為content的元素內所有命中選擇器article和aside的元素。但在有些情況下你卻不會希望sass使用這種後代選擇器的方式生成這種連線。

最常見的一種情況是當你為連結之類的元素寫:hover這種偽類時,你並不希望以後代選擇器的方式連線。比如說,下面這種情況sass就無法正常工作:

article a {
  color: blue;
  :hover { color: red }
}

這意味著color: red這條規則將會被應用到選擇器article a :hover,article元素內連結的所有子元素在被hover時都會變成紅色。這是不正確的!你想把這條規則應用到超連結自身,而後代選擇器的方式無法幫你實現。

解決之道為使用一個特殊的sass選擇器,即父選擇器。在使用巢狀規則時,父選擇器能對於巢狀規則如何解開提供更好的控制。它就是一個簡單的&符號,且可以放在任何一個選擇器可出現的地方,比如h1放在哪,它就可以放在哪。

article a {
  color: blue;
  &:hover { color: red }
}

當包含父選擇器識別符號的巢狀規則被開啟時,它不會像後代選擇器那樣進行拼接,而是&被父選擇器直接替換:

article a { color: blue }
article a:hover { color: red }

在為父級選擇器新增:hover等偽類時,這種方式非常有用。同時父選擇器識別符號還有另外一種用法,你可以在父選擇器之前新增選擇器。舉例來說,當用戶在使用IE瀏覽器時,你會通過JavaScript在<body>標籤上新增一個ie的類名,為這種情況編寫特殊的樣式如下:

#content aside {
  color: red;
  body.ie & { color: green }
}

/*編譯後*/
#content aside {color: red};
body.ie #content aside { color: green }

sass在選擇器巢狀上是非常智慧的,即使是帶有父選擇器的情況。當sass遇到群組選擇器(由多個逗號分隔開的選擇器形成)也能完美地處理這種巢狀。

2-2. 群組選擇器的巢狀;

在CSS裡邊,選擇器h1h2和h3會同時命中h1元素、h2元素和h3元素。與此類似,.buttonbutton會命中button元素和類名為.button的元素。這種選擇器稱為群組選擇器。群組選擇器 的規則會對命中群組中任何一個選擇器的元素生效。

.button, button {
  margin: 0;
}

當看到上邊這段程式碼時,你可能還沒意識到會有重複性的工作。但會很快發現:如果你需要在一個特定的容器元素內對這樣一個群組選擇器進行修飾,情況就不同了。css的寫法會讓你在群組選擇器中的每一個選擇器前都重複一遍容器元素的選擇器。

.container h1, .container h2, .container h3 { margin-bottom: .8em }

非常幸運,sass的巢狀特性在這種場景下也非常有用。當sass解開一個群組選擇器規則內嵌的規則時,它會把每一個內嵌選擇器的規則都正確地解出來:

.container {
  h1, h2, h3 {margin-bottom: .8em}
}

首先sass將.container和h1.container和h2.container和h3分別組合,然後將三 者重新組合成一個群組選擇器,生成你前邊看到的普通css樣式。對於內嵌在群組選擇器內的嵌 套規則,處理方式也一樣:

nav, aside {
  a {color: blue}
}

首先sass將nav和aaside和a分別組合,然後將二者重新組合成一個群組選擇器:

nav a, aside a {color: blue}

處理這種群組選擇器規則巢狀上的強大能力,正是sass在減少重複敲寫方面的貢獻之一。尤其在當巢狀級別達到兩層甚至三層以上時,與普通的css編寫方式相比,只寫一遍群組選擇器大大減少了工作量。

有利必有弊,你需要特別注意群組選擇器的規則巢狀生成的css。雖然sass讓你的樣式表看上去很小,但實際生成的css卻可能非常大,這會降低網站的速度。

關於選擇器巢狀的最後一個方面,我們看看sass如何處理組合選擇器,比如>、+和~的使用。你將看到,這種場景下你甚至無需使用父選擇器識別符號。

2-3. 子組合選擇器和同層組合選擇器:>、+和~;

上邊這三個組合選擇器必須和其他選擇器配合使用,以指定瀏覽器僅選擇某種特定上下文中的元素。

article section { margin: 5px }
article > section { border: 1px solid #ccc }

你可以用子組合選擇器>選擇一個元素的直接子元素。上例中,第一個選擇器會選擇article下的所有命中section選擇器的元素。第二個選擇器只會選擇article下緊跟著的子元素中命中section選擇器的元素。

在下例中,你可以用同層相鄰組合選擇器+選擇header元素後緊跟的p元素:

header + p { font-size: 1.1em }

你也可以用同層全體組合選擇器~,選擇所有跟在article後的同層article元素,不管它們之間隔了多少其他元素:

article ~ article { border-top: 1px dashed #ccc }

這些組合選擇器可以毫不費力地應用到sass的規則巢狀中。可以把它們放在外層選擇器後邊,或裡層選擇器前邊:

article {
  ~ article { border-top: 1px dashed #ccc }
  > section { background: #eee }
  dl > {
    dt { color: #333 }
    dd { color: #555 }
  }
  nav + & { margin-top: 0 }
}

sass會如你所願地將這些巢狀規則一一解開組合在一起:

article ~ article { border-top: 1px dashed #ccc }
article > footer { background: #eee }
article dl > dt { color: #333 }
article dl > dd { color: #555 }
nav + article { margin-top: 0 }

在sass中,不僅僅css規則可以巢狀,對屬性進行巢狀也可以減少很多重複性的工作。

2-4. 巢狀屬性;

在sass中,除了CSS選擇器,屬性也可以進行巢狀。儘管編寫屬性涉及的重複不像編寫選擇器那麼糟糕,但是要反覆寫border-styleborder-widthborder-color以及border-*等也是非常煩人的。在sass中,你只需敲寫一遍border:

nav {
  border: {
  style: solid;
  width: 1px;
  color: #ccc;
  }
}

巢狀屬性的規則是這樣的:把屬性名從中劃線-的地方斷開,在根屬性後邊新增一個冒號:,緊跟一個{ }塊,把子屬性部分寫在這個{ }塊中。就像css選擇器巢狀一樣,sass會把你的子屬性一一解開,把根屬性和子屬性部分通過中劃線-連線起來,最後生成的效果與你手動一遍遍寫的css樣式一樣:

nav {
  border-style: solid;
  border-width: 1px;
  border-color: #ccc;
}

對於屬性的縮寫形式,你甚至可以像下邊這樣來巢狀,指明例外規則:

nav {
  border: 1px solid #ccc {
  left: 0px;
  right: 0px;
  }
}

這比下邊這種同等樣式的寫法要好:

nav {
  border: 1px solid #ccc;
  border-left: 0px;
  border-right: 0px;
}

屬性和選擇器巢狀是非常偉大的特性,因為它們不僅大大減少了你的編寫量,而且通過視覺上的縮排使你編寫的樣式結構更加清晰,更易於閱讀和開發。

即便如此,隨著你的樣式表變得越來越大,這種寫法也很難保持結構清晰。有時,處理這種大量樣式的唯一方法就是把它們分拆到多個檔案中。sass通過對css原有@import規則的改進直接支援了這一特性。

3. 匯入SASS檔案;

css有一個特別不常用的特性,即@import規則,它允許在一個css檔案中匯入其他css檔案。然而,後果是隻有執行到@import時,瀏覽器才會去下載其他css檔案,這導致頁面載入起來特別慢。

sass也有一個@import規則,但不同的是,sass的@import規則在生成css檔案時就把相關檔案匯入進來。這意味著所有相關的樣式被歸納到了同一個css檔案中,而無需發起額外的下載請求。另外,所有在被匯入檔案中定義的變數和混合器(參見2.5節)均可在匯入檔案中使用。

使用sass的@import規則並不需要指明被匯入檔案的全名。你可以省略.sass或.scss檔案字尾(見下圖)。這樣,在不修改樣式表的前提下,你完全可以隨意修改你或別人寫的被匯入的sass樣式檔案語法,在sass和scss語法之間隨意切換。舉例來說,@import"sidebar";這條命令將把sidebar.scss檔案中所有樣式新增到當前樣式表中。

本節將介紹如何使用sass的@import來處理多個sass檔案。首先,我們將學習編寫那些被匯入的sass檔案,因為在一個大型sass專案中,這樣的檔案是你最常編寫的那一類。接著,瞭解集中匯入sass檔案的方法,使你的樣式可重用性更高,包括宣告可自定義的變數值,以及在某一個選擇器範圍內匯入sass檔案。最後,介紹如何在sass中使用css原生的@import命令。

通常,有些sass檔案用於匯入,你並不希望為每個這樣的檔案單獨地生成一個css檔案。對此,sass用一個特殊的約定來解決。

3-1. 使用SASS部分檔案;

當通過@import把sass樣式分散到多個檔案時,你通常只想生成少數幾個css檔案。那些專門為@import命令而編寫的sass檔案,並不需要生成對應的獨立css檔案,這樣的sass檔案稱為區域性檔案。對此,sass有一個特殊的約定來命名這些檔案。

此約定即,sass區域性檔案的檔名以下劃線開頭。這樣,sass就不會在編譯時單獨編譯這個檔案輸出css,而只把這個檔案用作匯入。當你@import一個區域性檔案時,還可以不寫檔案的全名,即省略檔名開頭的下劃線。舉例來說,你想匯入themes/_night-sky.scss這個區域性檔案裡的變數,你只需在樣式表中寫@import"themes/night-sky";。

區域性檔案可以被多個不同的檔案引用。當一些樣式需要在多個頁面甚至多個專案中使用時,這非常有用。在這種情況下,有時需要在你的樣式表中對匯入的樣式稍作修改,sass有一個功能剛好可以解決這個問題,即預設變數值。

3-2. 預設變數值;

一般情況下,你反覆宣告一個變數,只有最後一處宣告有效且它會覆蓋前邊的值。舉例說明:

$link-color: blue;
$link-color: red;
a {
color: $link-color;
}

在上例中,如果使用者在匯入你的sass區域性檔案之前聲明瞭一個$fancybox-width變數,那麼你的區域性檔案中對$fancybox-width賦值400px的操作就無效。如果使用者沒有做這樣的宣告,則$fancybox-width將預設為400px。

接下來我們將學習巢狀匯入,它允許只在某一個選擇器的範圍內匯入sass區域性檔案。

3-3. 巢狀匯入;

跟原生的css不同,sass允許@import命令寫在css規則內。這種匯入方式下,生成對應的css檔案時,區域性檔案會被直接插入到css規則內匯入它的地方。舉例說明,有一個名為_blue-theme.scss的區域性檔案,內容如下:

aside {
  background: blue;
  color: white;
}

然後把它匯入到一個CSS規則內,如下所示:

.blue-theme {@import "blue-theme"}

//生成的結果跟你直接在.blue-theme選擇器內寫_blue-theme.scss檔案的內容完全一樣。

.blue-theme {
  aside {
    background: blue;
    color: #fff;
  }
}

被匯入的區域性檔案中定義的所有變數和混合器,也會在這個規則範圍內生效。這些變數和混合器不會全域性有效,這樣我們就可以通過巢狀匯入只對站點中某一特定區域運用某種顏色主題或其他通過變數配置的樣式。

有時,可用css原生的@import機制,在瀏覽器中下載必需的css檔案。sass也提供了幾種方法來達成這種需求。

3-4. 原生的CSS匯入;

由於sass相容原生的css,所以它也支援原生的CSS@import。儘管通常在sass中使用@import時,sass會嘗試找到對應的sass檔案並匯入進來,但在下列三種情況下會生成原生的CSS@import,儘管這會造成瀏覽器解析css時的額外下載:

  • 被匯入檔案的名字以.css結尾;
  • 被匯入檔案的名字是一個URL地址(比如http://www.sass.hk/css/css.css),由此可用谷歌字型API提供的相應服務;
  • 被匯入檔案的名字是CSS的url()值。

這就是說,你不能用sass的@import直接匯入一個原始的css檔案,因為sass會認為你想用css原生的@import。但是,因為sass的語法完全相容css,所以你可以把原始的css檔案改名為.scss字尾,即可直接匯入了。

檔案匯入是保證sass的程式碼可維護性和可讀性的重要一環。次之但亦非常重要的就是註釋了。註釋可以幫助樣式作者記錄寫sass的過程中的想法。在原生的css中,註釋對於其他人是直接可見的,但sass提供了一種方式可在生成的css檔案中按需抹掉相應的註釋。

4. 靜默註釋;

css中註釋的作用包括幫助你組織樣式、以後你看自己的程式碼時明白為什麼這樣寫,以及簡單的樣式說明。但是,你並不希望每個瀏覽網站原始碼的人都能看到所有註釋。

sass另外提供了一種不同於css標準註釋格式/* ... */的註釋語法,即靜默註釋,其內容不會出現在生成的css檔案中。靜默註釋的語法跟JavaScriptJava等類C的語言中單行註釋的語法相同,它們以//開頭,註釋內容直到行末。

body {
  color: #333; // 這種註釋內容不會出現在生成的css檔案中
  padding: 0; /* 這種註釋內容會出現在生成的css檔案中 */
}

實際上,css的標準註釋格式/* ... */內的註釋內容亦可在生成的css檔案中抹去。當註釋出現在原生css不允許的地方,如在css屬性或選擇器中,sass將不知如何將其生成到對應css檔案中的相應位置,於是這些註釋被抹掉。

body {
  color /* 這塊註釋內容不會出現在生成的css中 */: #333;
  padding: 1; /* 這塊註釋內容也不會出現在生成的css中 */ 0;
}

你已經掌握了sass的靜默註釋,瞭解了保持sass條理性和可讀性的最基本的三個方法:巢狀、匯入和註釋。現在,我們要進一步學習新特性,這樣我們不但能保持條理性還能寫出更好的樣式。首先要介紹的內容是:使用混合器抽象你的相關樣式。

5. 混合器;

如果你的整個網站中有幾處小小的樣式類似(例如一致的顏色和字型),那麼使用變數來統一處理這種情況是非常不錯的選擇。但是當你的樣式變得越來越複雜,你需要大段大段的重用樣式的程式碼,獨立的變數就沒辦法應付這種情況了。你可以通過sass的混合器實現大段樣式的重用。

混合器使用@mixin識別符號定義。看上去很像其他的CSS @識別符號,比如說@media或者@font-face。這個識別符號給一大段樣式賦予一個名字,這樣你就可以輕易地通過引用這個名字重用這段樣式。下邊的這段sass程式碼,定義了一個非常簡單的混合器,目的是新增跨瀏覽器的圓角邊框。

@mixin rounded-corners {
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
}

然後就可以在你的樣式表中通過@include來使用這個混合器,放在你希望的任何地方。@include呼叫會把混合器中的所有樣式提取出來放在@include被呼叫的地方。如果像下邊這樣寫:

notice {
  background-color: green;
  border: 2px solid #00aa00;
  @include rounded-corners;
}

//sass最終生成:

.notice {
  background-color: green;
  border: 2px solid #00aa00;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
}

在.notice中的屬性border-radius-moz-border-radius和-webkit-border-radius全部來自rounded-corners這個混合器。這一節將介紹使用混合器來避免重複。通過使用引數,你可以使用混合器把你樣式中的通用樣式抽離出來,然後輕鬆地在其他地方重用。實際上,混合器太好用了,一不小心你可能會過度使用。大量的重用可能會導致生成的樣式表過大,導致載入緩慢。所以,首先我們將討論混合器的使用場景,避免濫用。

5-1. 何時使用混合器;

利用混合器,可以很容易地在樣式表的不同地方共享樣式。如果你發現自己在不停地重複一段樣式,那就應該把這段樣式構造成優良的混合器,尤其是這段樣式本身就是一個邏輯單元,比如說是一組放在一起有意義的屬性。

判斷一組屬性是否應該組合成一個混合器,一條經驗法則就是你能否為這個混合器想出一個好的名字。如果你能找到一個很好的短名字來描述這些屬性修飾的樣式,比如rounded-cornersfancy-font或者no-bullets,那麼往往能夠構造一個合適的混合器。如果你找不到,這時候構造一個混合器可能並不合適。

混合器在某些方面跟css類很像。都是讓你給一大段樣式命名,所以在選擇使用哪個的時候可能會產生疑惑。最重要的區別就是類名是在html檔案中應用的,而混合器是在樣式表中應用的。這就意味著類名具有語義化含義,而不僅僅是一種展示性的描述:用來描述html元素的含義而不是html元素的外觀。而另一方面,混合器是展示性的描述,用來描述一條css規則應用之後會產生怎樣的效果。

在之前的例子中,.notice是一個有語義的類名。如果一個html元素有一個notice的類名,就表明了這個html元素的用途:向用戶展示提醒資訊。rounded-corners混合器是展示性的,它描述了包含它的css規則最終的視覺樣式,尤其是邊框角的視覺樣式。混合器和類配合使用寫出整潔的html和css,因為使用語義化的類名亦可以幫你避免重複使用混合器。為了保持你的html和css的易讀性和可維護性,在寫樣式的過程中一定要銘記二者的區別。

有時候僅僅把屬性放在混合器中還遠遠不夠,可喜的是,sass同樣允許你把css規則放在混合器中。

5-2. 混合器中的CSS規則;

混合器中不僅可以包含屬性,也可以包含css規則,包含選擇器和選擇器中的屬性,如下程式碼:

@mixin no-bullets {
  list-style: none;
  li {
    list-style-image: none;
    list-style-type: none;
    margin-left: 0px;
  }
}

當一個包含css規則的混合器通過@include包含在一個父規則中時,在混合器中的規則最終會生成父規則中的巢狀規則。舉個例子,看看下邊的sass程式碼,這個例子中使用了no-bullets這個混合器:

ul.plain {
  color: #444;
  @include no-bullets;
}

sass的@include指令會將引入混合器的那行程式碼替換成混合器裡邊的內容。最終,上邊的例子如下程式碼:

ul.plain {
  color: #444;
  list-style: none;
}
ul.plain li {
  list-style-image: none;
  list-style-type: none;
  margin-left: 0px;
}

混合器中的規則甚至可以使用sass的父選擇器識別符號&。使用起來跟不用混合器時一樣,sass解開巢狀規則時,用父規則中的選擇器替代&。

如果一個混合器只包含css規則,不包含屬性,那麼這個混合器就可以在文件的頂部呼叫,寫在所有的css規則之外。如果你只是為自己寫一些混合器,這並沒有什麼大的用途,但是當你使用一個類似於Compass的庫時,你會發現,這是提供樣式的好方法,原因在於你可以選擇是否使用這些樣式。

接下來你將學習如何通過給混合器傳引數來讓混合器變得更加靈活和可重用。

5-3. 給混合器傳參;

混合器並不一定總得生成相同的樣式。可以通過在@include混合器時給混合器傳參,來定製混合器生成的精確樣式。當@include混合器時,引數其實就是可以賦值給css屬性值的變數。如果你寫過JavaScript,這種方式跟JavaScript的function很像:

@mixin link-colors($normal, $hover, $visited) {
  color: $normal;
  &:hover { color: $hover; }
  &:visited { color: $visited; }
}

當混合器被@include時,你可以把它當作一個css函式來傳參。如果你像下邊這樣寫:

a {
  @include link-colors(blue, red, green);
}

//Sass最終生成的是:

a { color: blue; }
a:hover { color: red; }
a:visited { color: green; }

當你@include混合器時,有時候可能會很難區分每個引數是什麼意思,引數之間是一個什麼樣的順序。為了解決這個問題,sass允許通過語法$name: value的形式指定每個引數的值。這種形式的傳參,引數順序就不必再在乎了,只需要保證沒有漏掉引數即可:

a {
    @include link-colors(
      $normal: blue,
      $visited: green,
      $hover: red
  );
}

儘管給混合器加引數來實現定製很好,但是有時有些引數我們沒有定製的需要,這時候也需要賦值一個變數就變成很痛苦的事情了。所以sass允許混合器宣告時給引數賦預設值。

5-4. 預設引數值;

為了在@include混合器時不必傳入所有的引數,我們可以給引數指定一個預設值。引數預設值使用$name: default-value的宣告形式,預設值可以是任何有效的css屬性值,甚至是其他引數的引用,如下程式碼:

@mixin link-colors(
    $normal,
    $hover: $normal,
    $visited: $normal
  )
{
  color: $normal;
  &:hover { color: $hover; }
  &:visited { color: $visited; }
}

如果像下邊這樣呼叫:@include link-colors(red)$hover和$visited也會被自動賦值為red。

混合器只是sass樣式重用特性中的一個。我們已經瞭解到混合器主要用於樣式展示層的重用,如果你想重用語義化的類呢?這就涉及sass的另一個重要的重用特性:選擇器繼承。

6. 使用選擇器繼承來精簡CSS;

使用sass的時候,最後一個減少重複的主要特性就是選擇器繼承。基於Nicole Sullivan面向物件的css的理念,選擇器繼承是說一個選擇器可以繼承為另一個選擇器定義的所有樣式。這個通過@extend語法實現,如下程式碼:

//通過選擇器繼承繼承樣式
.error {
  border: 1px solid red;
  background-color: #fdd;
}
.seriousError {
  @extend .error;
  border-width: 3px;
}

在上邊的程式碼中,.seriousError將會繼承樣式表中任何位置處為.error定義的所有樣式。以修飾的html元素最終的展示效果就好像是。相關元素不僅會擁有一個3px寬的邊框,而且這個邊框將變成紅色的,這個元素同時還會有一個淺紅色的背景,因為這些都是在.error裡邊定義的樣式。

.seriousError不僅會繼承.error自身的所有樣式,任何跟.error有關的組合選擇器樣式也會被.seriousError以組合選擇器的形式繼承,如下程式碼:

//.seriousError從.error繼承樣式
.error a{  //應用到.seriousError a
  color: red;
  font-weight: 100;
}
h1.error { //應用到hl.seriousError
  font-size: 1.2rem;
}

如上所示,在的html元素內的超連結也會變成紅色和粗體。

本節將介紹與混合器相比,哪種情況下更適合用繼承。接下來在探索繼承的工作細節之前,我們先了解一下繼承的高階用法。最後,我們將看看使用繼承可能會有哪些坑,學習如何避免這些坑。

6-1. 何時使用繼承;

5-1節介紹了混合器主要用於展示性樣式的重用,而類名用於語義化樣式的重用。因為繼承是基於類的(有時是基於其他型別的選擇器),所以繼承應該是建立在語義化的關係上。當一個元素擁有的類(比如說.seriousError)表明它屬於另一個類(比如說.error),這時使用繼承再合適不過了。

這有點抽象,所以我們從幾個方面來闡釋一下。想象一下你正在編寫一個頁面,給html元素新增類名,你發現你的某個類(比如說.seriousError)另一個類(比如說.error)的細化。你會怎麼做?

  • 你可以為這兩個類分別寫相同的樣式,但是如果有大量的重複怎麼辦?使用sass時,我們提倡的就是不要做重複的工作。
  • 你可以使用一個選擇器組(比如說.error.seriousError)給這兩個選擇器寫相同的樣式。如果.error的所有樣式都在同一個地方,這種做法很好,但是如果是分散在樣式表的不同地方呢?再這樣做就困難多了。
  • 你可以使用一個混合器為這兩個類提供相同的樣式,但當.error的樣式修飾遍佈樣式表中各處時,這種做法面臨著跟使用選擇器組一樣的問題。這兩個類也不是恰好有相同的 樣式。你應該更清晰地表達這種關係。
  • 綜上所述你應該使用@extend。讓.seriousError從.error繼承樣式,使兩者之間的關係非常清晰。更重要的是無論你在樣式表的哪裡使用.error.seriousError都會繼承其中的樣式。

現在你已經更好地掌握了何時使用繼承,以及繼承有哪些突出的優點,接下來我們看看一些高階用法。

6-2. 繼承的高階用法;

任何css規則都可以繼承其他規則,幾乎任何css規則也都可以被繼承。大多數情況你可能只想對類使用繼承,但是有些場合你可能想做得更多。最常用的一種高階用法是繼承一個html元素的樣式。儘管預設的瀏覽器樣式不會被繼承,因為它們不屬於樣式表中的樣式,但是你對html元素新增的所有樣式都會被繼承。

接下來的這段程式碼定義了一個名為disabled的類,樣式修飾使它看上去像一個灰掉的超連結。通過繼承a這一超連結元素來實現:

.disabled {
  color: gray;
  @extend a;
}

假如一條樣式規則繼承了一個複雜的選擇器,那麼它只會繼承這個複雜選擇器命中的元素所應用的樣式。舉例來說, 如果[email protected], 那麼.important.error和h1.important.error的樣式都會被.seriousError繼承, 但是.important或者.error下的樣式則不會被繼承。這種情況下你很可能希望.seriousError能夠分別繼承.important或者.error下的樣式。

如果一個選擇器序列(#main .seriousError)@extend另一個選擇器(.error),那麼只有完全匹配#main .seriousError這個選擇器的元素才會繼承.error的樣式,就像單個類 名繼承那樣。擁有的#main元素之外的元素不會受到影響。

像#main .error這種選擇器序列是不能被繼承的。這是因為從#main .error中繼承的樣式一般情況下會跟直接從.error中繼承的樣式基本一致,細微的區別往往使人迷惑。

現在你已經瞭解了通過繼承能夠做些什麼事情,接下來我們將學習繼承的工作細節,在生成對應css的時候,sass具體幹了些什麼事情。

6-3. 繼承的工作細節;

跟變數和混合器不同,繼承不是僅僅用css樣式替換@extend處的程式碼那麼簡單。為了不讓你對生成的css感覺奇怪,對這背後的工作原理有一定了解是非常重要的。

@extend背後最基本的想法是,如果.seriousError @extend .error, 那麼樣式表中的任何一處.error都用.error.seriousError這一選擇器組進行替換。這就意味著相關樣式會如預期那樣應用到.error和.seriousError。當.error出現在複雜的選擇器中,比如說h1.error.error a或者#main .sidebar input.error[type="text"],那情況就變得複雜多了,但是不用擔心,sass已經為你考慮到了這些。

關於@extend有兩個要點你應該知道。

  • 跟混合器相比,繼承生成的css程式碼相對更少。因為繼承僅僅是重複選擇器,而不會重複屬性,所以使用繼承往往比混合器生成的css體積更小。如果你非常關心你站點的速度,請牢記這一點。
  • 繼承遵從css層疊的規則。當兩個不同的css規則應用到同一個html元素上時,並且這兩個不同的css規則對同一屬性的修飾存在不同的值,css層疊規則會決定應用哪個樣式。相當直觀:通常權重更高的選擇器勝出,如果權重相同,定義在後邊的規則勝出。

混合器本身不會引起css層疊的問題,因為混合器把樣式直接放到了css規則中,而繼承存在樣式層疊的問題。被繼承的樣式會保持原有定義位置和選擇器權重不變。通常來說這並不會引起什麼問題,但是知道這點總沒有壞處。

6-4. 使用繼承的最佳實踐;

通常使用繼承會讓你的css美觀、整潔。因為繼承只會在生成css時複製選擇器,而不會複製大段的css屬性。但是如果你不小心,可能會讓生成的css中包含大量的選擇器複製。

避免這種情況出現的最好方法就是不要在css規則中使用後代選擇器(比如.foo .bar)去繼承css規則。如果你這麼做,同時被繼承的css規則有通過後代選擇器修飾的樣式,生成css中的選擇器的數量很快就會失控:

.foo .bar { @extend .baz; }
.bip .baz { a: b; }

在上邊的例子中,sass必須保證應用到.baz的樣式同時也要應用到.foo .bar(位於的元素內的的元素)。例子中有一條應用到.bip .baz(位於的元素內的的元素)的css規則。當這條規則應用到.foo .bar時,可能存在三種情況,如下程式碼:

<!-- 繼承可能迅速變複雜 -->
<!-- Case 1 -->
<div class="foo">
  <div class="bip">
    <div class="bar">...</div>
  </div>
</div>
<!-- Case 2 -->
<div class="bip">
  <div class="foo">
    <div class="bar">...</div>
  </div>
</div>
<!-- Case 3 -->
<div class="foo bip">
  <div class="bar">...</div>
</div>

為了應付這些情況,sass必須生成三種選擇器組合(僅僅是.bip .foo .bar不能覆蓋所有情況)。如果任何一條規則裡邊的後代選擇器再長一點,sass需要考慮的情況就會更多。實際上sass並不總是會生成所有可能的選擇器組合,即使是這樣,選擇器的個數依然可能會變得相當大,所以如果允許,儘可能避免這種用法。

值得一提的是,只要你想,你完全可以放心地繼承有後代選擇器修飾規則的選擇器,不管後代選擇器多長,但有一個前提就是,不要用後代選擇器去繼承。

7. 小結;

本文介紹了sass最基本部分,你可以輕鬆地使用sass編寫清晰、無冗餘、語義化的css。對於sass提供的工具你已經有了一個比較深入的瞭解,同時也掌握了何時使用這些工具的指導原則。

變數是sass提供的最基本的工具。通過變數可以讓獨立的css值變得可重用,無論是在一條單獨的規則範圍內還是在整個樣式表中。變數、混合器的命名甚至sass的檔名,可以互換通用_和-。同樣基礎的是sass的巢狀機制。巢狀允許css規則內巢狀css規則,減少重複編寫常用的選擇器,同時讓樣式表的結構一眼望去更加清晰。sass同時提供了特殊的父選擇器識別符號&,通過它可以構造出更高效的巢狀。

你也已經學到了sass的另一個重要特性,樣式匯入。通過樣式匯入可以把分散在多個sass檔案中的內容合併生成到一個css檔案,避免了專案中有大量的css檔案通過原生的css@import帶來的效能問題。通過巢狀匯入和預設變數值,匯入可以構建更強有力的、可定製的樣式。混合器允許使用者編寫語義化樣式的同時避免視覺層面上樣式的重複。你不僅學到了如何使用混合器減少重複,同時學習到了如何使用混合器讓你的css變得更加可維護和語義化。最後,我們學習了與混合器相輔相成的選擇器繼承。繼承允許你宣告類之間語義化的關係,通過這些關係可以保持你的css的整潔和可維護性。