What is Sass?

我們可以想像一下…
假設你要洗衣服,你需要按洗衣機的觸控面板才能啟動。
Sass就像是你使用洗衣觸控面板功能,你的指令會轉化成洗衣機懂的語言,才能啟動洗衣機執行洗衣服。

🎇 Sass(英文全稱:Syntactically Awesome Stylesheets),是一個開發的層疊樣式表語言。 
Sass是一個將指令碼解析成CSS的手稿語言,即SassScript。Sass包括兩套語法。
sass是舊版本,業界主流是scss。
最開始的語法叫做「縮排語法」,使用縮排來區分代碼塊,並且用換行將不同規則分隔開。
而較新的語法叫做「SCSS」,使用和CSS一樣的塊語法,即使用大括號將不同的規則分開,使用分號將具體的樣式分開。
通常情況下,這兩套語法通過.sass和.scss兩個副檔名區分開。

🐥 關於 Sass 的更多資訊:
https://ithelp.ithome.com.tw/articles/10126703

  • CSS 預處理器的由來

    因為網路的普及以及人們對網站愈來愈高的期待,前端開發的守備範圍持續擴大,網站也變得愈來愈複雜。人們需要尋找「更有效率的 CSS 撰寫/管理方式」,來避免上述種種問題。

    因此,就出現了「CSS 預處理器 (CSS Preprocessor) 」這樣的解決方案——它本身是 CSS 語法的擴充,讓開發者能夠處理抽象邏輯,例如變數、模組、與繼承等等。

    透過這種方式,開發者在自己的開發環境裡透過預處理器,「用類似程式語言的方式設定樣式」,要交接給瀏覽器時,再編譯成底層的 CSS 語言。

    目前流行的 CSS 預處理器有:

    • Sass:是最早誕生的預處理器,源於 Ruby 社群,發展成熟,普及度高,與 Less 相互影響,持續演進中。
    • Less:稍晚於 Sass,強調兼容性並且更容易上手,也擁有自己的支持社群,例如著名的 Twitter Bootstrap 採用了 Less。
    • Stylus:本質上和 Less/Sass 類似,只是更為 Node.js 社群量身打造。

    🐥 不同工具之間大同小異,本質都在解決一樣的問題,只是各有各的側重點,只需要學會其中一種,基本上就可以理解要點。

Sass 中的 & 是什麼 ?

“ & “ 可以看作是串聯選擇器的連接符。
連接符引用父層選擇器作替代, & 連接符會代替父層選擇器: ,然後使鏈結懸停並改變鏈接的顏色爲其他顏色。
“&” 省下了重複撰寫的時間,但過於巢狀也會導致程式碼不好維護,盡量在三層內解決!

基礎概念:

在CSS中,要想給一個元素賦予一定的樣式,我們必須得先取到這個元素。那麼就得需要選擇器,通過選擇器來選擇指定元素,然後賦予所需的樣式。

而CSS選擇器有很多種,比如層次選擇器中的後代選擇器兄弟選擇器通用兄弟選擇器等。

而這些選擇器都通過元素與元素之間的關係來確定的,比如:

1
2
.parent .child {...}

除了這些選擇器,還有偽類選擇器:

1
2
.ele:after{...}

有時候還有多類選擇器

1
2
.className1.className2{...}

這些選擇器在CSS中都是基礎知識,很多同學對其來說並不陌生。今天要說的也不是選擇器如何用,而是想說說,如何在編寫代碼的時候,少寫選擇器,就能實現他們之間的依賴關係。

引用父層選擇器 的連接符 &

在CSS中,這種想法是無法實現的,但在Sass中,可以輕鬆的通過**連接符&**來實現。

我們先來回憶一下,CSS中常見的一組樣式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*頁面中鏈接的顏色*/
a {
clolor: #ff3366;
}
a:hover {
color: #cc0033;
}
/*主選單中鏈接的顏色*/
.nav-menu a {
color: #ff668c;
}
.nav-menu a:hover {
color: #ff99b3;
}
.nav-menu a.active {
color: #ff0040;
}
/*頁尾選單中鏈接的顏色*/
.footer-menu a {
color: #ff1a53;
}
.footer-menu a:hover {
color: #cc0033;
}

這是一組控制頁面鏈接顏色的樣式代碼,首先在樣式中定義了共通樣的連結文預設顏色,而主選單和頁尾選單中連結文預設顏色各不相同,我們需要通過類名.nav-menu.footer-menu來覆蓋默認的樣式。

這樣我們在寫樣式的時候,在選擇器這一部分,我們都需要書寫相同的一個部分:

1
aa:hover

或許你覺得這有什麼的,真是大驚小怪。但是,如果你的選擇器偏長,重複的代碼偏多,一定會影響您的開發速度,從而影響你的效率。

那麼在Sass中,通過**連接符&**可以幫助我們避免這樣的問題,而且還可以實現一些其他的效果。

與偽類的結合

偽類和偽元素在CSS中是常用的一種方式。

比如最常見的是連結網址的偽類或者說偽元素:after:before的使用。

大家常看到的就是清除浮動的clearfix:

1
2
3
4
5
6
7
8
9
10
.clearfix:before,
.clearfix:after {
content:"";display:table;
}
.clearfix:after {
clear:both;overflow:hidden;
}
.clearfix {
*zoom: 1;
}

那麼在Sass中,使用&會變得更簡單,更方便:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$lte-ie: true !default;

.clearfix {
@if $lte-ie {
*zoom: 1;
}

&:before,
&:after {
content: "";
display: table;
}
&:after {
clear: both;
overflow: hidden;
}
}

這個簡單的例子非常明確說明,在Sass中可以使用&和偽元素、偽類配合使用,而且使用的方法非常簡單。就是用&替代元素自身。

多類選擇器.className1 .className2在CSS中並不常見(主要因為在IE6中解析有所偏差),但還是非常有用。

比如說增加一個懸浮效果的時候,可以看到這樣的樣式代碼:

1
2
3
.mod.on {
color: green;
}

那麼在Sass中,同樣可以使用&來替代選擇器.mod

1
2
3
4
5
.mod {
&.on{
color: green;
}
}

這裡需要特別的注意,&和相連的類名之間不能有任何的空格,不然就會變成CSS選擇器中的後代選擇器:

1
2
3
4
5
.mod {
& .on {
color: green;
}
}

編譯出來的CSS就成了:

1
2
3
.mod .on {
color: green;
}

在Sass中還有同等效果的寫法是Sass的直接嵌套:

1
2
3
4
5
.mod {
.on {
color: green;
}
}
後代選擇器

正如上面的示例所示,在Sass中可以通過Sass的層級嵌套來實現後代選擇器。嵌套的越深,層級越多:

1
2
3
4
5
6
7
.nav-menu {
li {
a {
color: green;
}
}
}

生成的CSS:

1
2
3
.nav-menu li a {
color: green;
}

看到這里大家或許會問,這跟&有什麼關係呢?因為在選擇器前面加上&符和不加上&符將得到的效果是一樣。

但大家可能也碰到過,有時候在Sass先寫了子元素的效果,但還需要另一個地方來覆蓋,那麼&將會起到大作用。

先來看一個簡單的示例:

1
2
3
4
5
6
a {
color: red;
.nav-menu &{
color: blue;
}
}

生成的CSS:

1
2
3
4
5
6
a {
color: red;
}
.nav-menu a {
color: blue;
}

示例非常簡單的說明了一切,&在選擇器後面時的功能。但這裡需要特別的注意,&寫在後面的,前面必須要有空格。不然Sass在編譯時將會報錯:

1
2
3
4
Change detected to: test.scss
error test.scss (Line 78: Invalid CSS after " .nav-menu": expected
"{", was "&{"
"&" may only be used at the beginning of a compound selector.)

綜合上面所述,我們回到文章最開頭的那段CSS代碼,我們只需要靈活的運用好&,就可以輕鬆的完成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
$color: #444;
$bg-color: #f5f5f5;
$link-color: #f36;
a {
clolor: $link-color;

&:hover {
color: darken($link-color, 20%);
}

//Main menu Link Color
.nav-menu & {
color: lighten($link-color, 10%);

&:hover {
color: lighten($link-color, 20%);
}

&.active {
color: darken($link-color, 10%);
}
}

//Footer menu link color
.footer-menu & {
color: darken($link-color, 5%);

&:hover {
color: darken($link-color, 20%);
}
}

//Footer menu link color
.footer-menu & {
color: darken($link-color, 5%);

&:hover {
color: darken($link-color, 20%);
}
}
}
相鄰兄弟選擇

在CSS選擇器中還有一種是相鄰兄弟選擇器。如:

1
label + input[type="text"]{...}

input[type="text"]元素緊鄰label元素。

在Sass中,同樣可以使用&符來替代其中某個元素:

1
2
3
4
5
6
lable {
color: green;
& + input[type="text"] {
border: 1px solid green;
}
}

編譯CSS:

1
2
3
4
5
6
lable {
color: green;
}
lable + input[type="text"] {
border: 1px solid green;
}

在這裡僅僅想通過這樣一個簡單的示例來演示&在選擇器中所承載的對象,換句話說,就是&替代的是哪一處元素。

這跟其所處的位置以及對應使用的選擇器符號很有關係。

媒體查詢中的嵌套功能( Nested Rules )

在Sass中,媒體查詢配合&符,可以輕鬆的讓你管理幾個不同版式的樣式(方便管理不同斷點下的樣式),先來看一個簡單的示例:

1
2
3
4
5
6
7
8
9
.main {
float: left;
width: 45em;@media (max-width: 480px) {
& {
float: none;
width: 100%;
}
}
}

編譯出來的CSS:

1
2
3
4
5
6
7
8
9
10
.main {
float: left;
width: 45em;
}
@media (max-width: 480px) {
.main {
float: none;
width: 100%;
}
}

這樣在製作響應式設計的時候是不是變得非常的簡單,而且易於管理你的代碼。

不過除了上面種方式之外,我們還可以採用下面的方式與媒體查詢配合使用:

1
2
3
4
5
6
7
8
9
.main {
float: left;
width: 45em;& {
@media (max-width: 480px) {
float: none;
width: 100%;
}
}
}

這段SCSS代碼編譯出來的CSS和前面的是一模一樣的。

& 符在Sass中存在的問題

前面主要演示了&在Sass中如何讓你更好的使用您的選擇器,但是&在Sass中運用也存在一些問題。接下來一起看看&在Sass中存在的問題,以及如何避免這些問題。

說到這個問題,我們繼續拿CSS中的BEM來說事。

先簡單說明一下BEM的模式:

1
2
3
.block{...}
.block__element{...}
.block--modifier{...}

很想在Sass中通過下面的方式實現BEM的模式:

1
2
3
4
5
.block{
...
&__element{...}
&--modifier{...}
}

可是這樣書寫,編譯器無法編譯,將會報出錯誤信息:

1
2
Invalid CSS after " &": expected "{", was "__element{"
"__element" may only be used at the beginning of a compound selector.)

此時很多人有可能想到了使用Sass中的插件#{&}的方式來替代.block

1
2
3
4
5
6
7
8
9
.block{
clolor: red;
#{&}__element{
color: green;
}
#{&}--modifier{
color: blue;
}
}

但編譯出來的CSS代碼還是不盡人意:

1
2
3
4
5
6
7
8
9
.block {
clolor: red;
}
.block .block__element {
color: green;
}
.block .block--modifier {
color: blue;
}

編譯出來的CSS代碼雖然有效,但並不是好的CSS代碼。

而且這樣編譯出來的CSS也離開了BEM的初衷。

這也是&在Sass中當作插值使用不盡人意之處。

不過這種現像也有方法可以解決。

簡單一點的:

1
2
3
4
5
6
7
8
9
10
11
$last-rule: null;
.block{
clolor: red;
$last-rule: &;
}
#{$last-rule}__element{
color: green;
}
#{$last-rule}--modifier{
color: blue;
}

編譯出來的CSS:

1
2
3
4
5
6
7
8
9
.block {
clolor: red;
}
.block__element {
color: green;
}
.block--modifier {
color: blue;
}

這種方法有兩個關鍵之處:

定義一個變量$last-rule,賦予變量值為null主要用來代表相同的前綴;
在B中通過$last-rule:&來賦予新值也就代表了對應的綴。

**特別聲明:採用這種方法,編譯的時候會提示警告信息,但並不會影響代碼**

編譯:

1
2
3
Assigning to global variable "$last-rule" by default is deprecated.
In future versions of Sass, this will create a new local variable.
If you want to assign to the global variable, use "$last-rule: & !global" instead.

值得慶幸的是,在Sass的測試版本中有一個新的功能@at-root

使用他配合#{&}可以輕鬆的解決這個問題。

1
2
3
4
5
6
7
8
9
10
.block {
color: red;
@at-root #{&}__element{
color: green;
}

@at-root #{&}--modifier{
color: blue;
}
}

編譯出來的CSS:

1
2
3
4
5
6
7
8
9
.block {
clolor: red;
}
.block__element {
color: green;
}
.block--modifier {
color: blue;
}

Sass中的連接符&讓你在嵌套和插值的使用過程時,會讓你憂,會讓你喜。
憂的是一不小心使用不對帶來錯誤,或者讓你的代碼變得冗餘。
喜的是讓你控制選擇器變得更加的靈活。


What is Sass?
http://example.com/2023/09/19/20220822/
Author
Daphne Shen
Posted on
September 19, 2023
Licensed under