前端CSS的工程化——掌握Sass這四大特性就夠了


初遇 CSS,一見傾心

記得剛遇見css的時候,咱像是見了美人兒一樣,簡直是愛不釋手啊,簡簡單單寫幾行算不上代碼的代碼,就能做出這么漂亮的東西,這也成了咱前端之路的最初動力。

然而,隨着項目體量和頁面復雜度的增加,咱很快就發現這美人兒非但不漂亮,而且缺胳膊少腿兒的:

  • 缺少模塊系統。模塊系統是軟件工程化的基石,CSS 的這個缺陷對前端項目的工程化管理造成了很大阻力,導致開發大型應用時編碼和維護都異常困難。js 一開始也沒有模塊系統,后來各種輪子頻出,什么CMD,AMD,UMD全蹦出來了,亂哄哄的,好在 ES6 從語言層面引入了模塊系統才終結了這種亂象,以后 js 的模塊化終於可以統一了。css 你怎么不好好向你的好基友 js 學習呢,人家都有了,你還傻了吧唧的一點動靜都沒有。
  • 沒有變量機制。這對控制多個地方會引用到的屬性值很不方便。比如一個顏色值,頁面好多地方用到,設計MM突然心血來潮把這個值換成了另一個顏色,咱們怎么辦,ctrl+f 全局替換?萬一換掉了不該換的,或者漏掉了幾個怎么辦。
  • 嵌套的層級寫法非常蛋疼。經常會出現
    .page .content .left-side .profile .name{};
    .page .content .left-side .profile .age{};

    這種看起來很不爽,寫起來更不爽的寫法。這是程序員最不能忍受的——重復。
  • 復用困難。復用是軟件工程的核心思想,css 不僅沒提供模塊系統,而且巧妙地避開了工程化的諸多實踐。更加覺得 css 這門語言設計的跟鬧着玩兒似的。
  • blabla.. 其它的都不是很嚴重啦。

CSS 沒有模塊系統,你當我 @import 是空氣?
CSS 的 @import 規則是可以在一個 css 文件導入其他 css 文件,但這貨需要執行到它時才能觸發瀏覽器去下載它所 import 來的 css 文件,導致頁面加載起來特別慢,還不如直接在 里寫一大坨 標簽的引入效率高,是名副其實的雞肋功能,演員一般的存在,用你一次算我輸。

有需求就會有市場,Sass(Syntactically Awesome Style Sheets) 應運而生。

老規矩,先來看看 Sass 官網的原話:

Sass 是世界上最成熟、最穩定、最強大的專業級 CSS 擴展語言!

這貨還真是一點也不謙虛,“最成熟,最穩定,最強大”。

通過這幾年項目中的實際運用,咱發現這句簡短霸氣的描述其實並沒有絲毫的浮誇,Sass 的確厲害,完全可以 hold 住這三個“最”字,實至名歸。

什么是預處理器
預處理器是在程序源文件被編譯之前根據預處理指令對程序源文件進行處理的程序。說白了,預處理器只不過是一個文本替換工具而已。CSS 預處理器則是通過將有特殊語法和指令的源代碼處理成瀏覽器可使用的 CSS 文件的程序。

是 Sass 還是 SCSS?
SCSS 是 Sass 3 引入的新語法,語法上完全兼容原生 CSS,功能上完全繼承 Sass,可以說是 CSS 和 Sass 的完美融合。SCSS 之於 Sass 猶如 CSS3 之於 CSS,ES6 之於 JS。所以別糾結,其實是一個東西啦。

接下來就細數 Sass 帶給咱們的四大實用特性,想必你一定已經使用過它們中的一個或幾個。

一、嵌套寫法

想想之前咱們是怎樣寫原生 css 的:

 .page .content .left-side .profile .name{
     font-size: 2rem;
 }
 .page .content .left-side .profile .age{
     color: red;
 }
 

現在使用 scss 可以這樣寫:

.page{
    .content{
        .left-side{
            .profile{
                .name{
                    font-size: 2rem;
                }
                .age{
                    color: red;
                }
            }
        }
    }
}
 

編譯后

.page .content .left-side .profile .name{font-size: 2rem;}
.page .content .left-side .profile .age{color: red;}
 

這種嵌套寫法的好處是顯然的:

  • 結構清晰簡潔,並且可與 html 文檔結構對應起來;
  • 減少了大量冗余重復的選擇器編碼;

二、屬性值的復用——定義變量

變量一直是所有編程語言的標准配置。然而 CSS 就沒有,再次證明 CSS 可能是一門假語言。好在 Sass 補上了這個短板。

沒有變量之前的代碼(這里以定義一系列表示成功風格的樣式組件為例):

.success-bg{
    background: #dff0d8;
}
.success-panel{
    .panel-heading{
        background: #dff0d8;
    }
    .panel-body{
        border: 1px solid #dff0d8;
    }
}
 

使用了變量后的代碼:

$success-color: #dff0d8;

.success-bg{
    background: $success-color;
}
.success-panel{
    .panel-heading{
        background: $success-color;
    }
    .panel-body{
        border: 1px solid $success-color;
    }
}
 

使用變量的好處是顯而易見的:

  • 方便了多人協同作戰,將頻繁使用的屬性值定義成變量放在單獨的文件里,各個開發人員可方便引用而不必再關注這些小細節,有語義的變量名使用起來也要比單調的CSS值容易的多;
  • 極大地增強了代碼的可維護性,便於局部和全局的樣式風格統一控制;

三、文件級的復用——模塊系統

模塊化是軟件工程的第一要務,是大型項目的必需建築。軟件工程的主要目標就是控制復雜度,這也正是模塊化的目的。通過將一個大型復雜的工程拆解成一個個的小模塊,使得校驗、調試、測試都輕而易舉。

CSS原生的 @import 提供了一個並沒有卵用的假模塊系統。Sass 對 @import 進行了拓展,實現了一個真正意義上甚至功能更強大的模塊系統。Sass 選擇對 @import 進行擴展,而不是新建一個指令,可見 import 這個關鍵字的語義之強,JavaScript 模塊系統的關鍵字也是 import

沒有模塊系統之前:

<!-- index.html -->
<link rel="stylesheet" href="/your/site/common.css">
<link rel="stylesheet" href="/your/site/popup.css">
<link rel="stylesheet" href="/your/site/module_a.css">
<link rel="stylesheet" href="/your/site/site.css">
 

有了模塊系統之后:

/* site.scss */
@import "common";
@import "popup";
@import "module_a";
 
<!-- index.html -->
<link rel="stylesheet" href="/your/site/site.css">
 

好處嘛自然不用多說了:

  • 增刪改模塊以后是 css 自己家的事,別麻煩別人,不用再去動 html 了吼;-
  • 模塊系統使得項目並不會隨着業務復雜度增加而變得更加復雜。增加功能時只需要橫向擴展就行了,不會縱向延伸,從而能始終保證每個模塊完整而簡單;-

四、展示層的復用——混合指令

混合(mixin)特別類似於 JavaScript 中的函數,然而 Sass 提供了用於表達式計算的 @function 函數指令,這里就不好這么類比了。但其實就是這么個東西,調用的時候會返回一段樣式。

比如下面一段存在重復樣式的代碼。

復用之前:

.description{
    color: red;
    border: 1px solid #e3e3e3;
    border-radius: 2px;
}
.article{
    color: #444;
    border: 1px solid #e3e3e3;
    border-radius: 2px;
}
 

稍作優化:

.description, .article{
    border: 1px solid #e3e3e3;
    border-radius: 2px;
}
.description{
    color: red;
}
.article{
    color: #444;
}
 

似乎不錯,但是之后再新加類似樣式時,

.description, .article, .style01, .style02{
    border: 1px solid #e3e3e3;
    border-radius: 2px;
}
.
.
.
.style01{}
.style02{}
 

每次都要改兩個地方,很麻煩,很容易漏,尤其是將通用樣式分離出來的話更容易出錯。

再做優化:

.grey-border-radius{
    border: 1px solid #e3e3e3;
    border-radius: 2px;
}
.description{
    color: red;
}
.article{
    color: #444;
}
 

似乎好了一點,但這樣的話,html 每個使用的標簽都需要多加上一個 .grey-border-radius 類。很顯然這是多余的。這種做法可以說是“湊合”。

使用 Sass 復用之后:

@mixin grey-border-radius{
    border: 1px solid #e3e3e3;
    border-radius: 2px;
}
.description{
    @include grey-border-radius;
    color: red;
}
.article{
    @include grey-border-radius;
    color: #444;
}
 

編譯后的 css 輸出:

.description {
  border: 1px solid #e3e3e3;
  border-radius: 2px;
  color: red;
}
.article {
  border: 1px solid #e3e3e3;
  border-radius: 2px;
  color: #444;
}
 

看到了吧,這種做法簡直“完美”:

  • 抽離公共的樣式片段,便於多處復用;
  • 將公共的樣式片段放在單獨的文件里,便於項目的多個文件復用;
  • 對 html 的使用沒有任何要求,css 自己家的事自己關起門來解決,絕不麻煩別人;

其他不常用且慎用的強大特性

如果熟練合理地運用上面的四大特性,你已經是CSS代碼工程化方面的磚家了,所寫出來的代碼必是清晰易維護的。Sass 提供了更多的功能,但對普通開發者來講,上面的四點只要使用熟練,已經完全夠用了,其他的可看可不看。下面提供的功能希望大家慎用,有的是出於性能考慮,有的則是從開發維護的角度考慮。尤其不要為了秀技術而去使用它們,過猶不及,事緩則圓,此為中庸之道。

# 語義層的復用——繼承機制

繼承是面向對象程序設計的三大特性之一,這也是為什么說它是語義層復用的原因。你可以說一個錯誤信息框繼承了一個信息框,而不能說一個錯誤信息框繼承了一個灰色圓角,雖然也是可以強行這么說,但難免有些別扭哈哈。

比如說下面定義一組信息框的樣式,包括默認,成功和錯誤的樣式。

使用繼承之前:

.msg{
    border: 1px solid #e3e3e3;
    background: #dff0d8;
}
.msg-success{
    color: #4cae4c;
}
.msg-error{
    color: #d43f3a;
}
 

同樣是上面說到的問題,編寫 html 時每個使用的標簽都需要多加上一個 .msg 類,很多余。

使用繼承之后:

.msg{
    border: 1px solid #e3e3e3;
    background: #dff0d8;
}
.msg-success{
    @extend .msg;
    color: #4cae4c;
}
.msg-error{
    @extend .msg;
    color: #d43f3a;
}
 

編譯后

.msg, .msg-success, .msg-error {
  border: 1px solid #e3e3e3;
  background: #dff0d8;
}
.msg-success {
  color: #4cae4c;
}
.msg-error {
  color: #d43f3a;
}
 

可以看出,上面的效果使用混合(mixin)也可以完成。但不同的是:繼承拷貝的是選擇器,而混合(mixin)拷貝的是樣式片段。

使用混合(mixin)還是繼承(extend)?
你肯定以為既然繼承拷貝的是選擇器,而混合拷貝的是大段的樣式,那當然是優先選擇繼承了。然而恰恰相反,推薦做法是 盡可能使用混合(mixin),具體原因 戳這里

# 用於復雜計算的函數

這個功能主要用於值的計算,和 JavaScript 中的函數類似。

比如移動端開發時可以封裝成一個函數用於把 px 轉成 rem。

$baseFontSize: 20;
@function px2rem($val) {
  @return $val/$baseFontSize + rem;
}

.big-text{
    font-size: px2rem(30);
}
 

編譯后:

.big-text {
  font-size: 1.5rem;
}
 

這樣在拿到設計MM給的視覺稿之后就可以直接使用 px 進行測量使用了。

# 完善的控制流

控制流即程序語言中的 if/elseforwhile 等控制語句。Sass 同樣提供了指令實現:

  • @if
  • @for
  • @each
  • @while

它們通常配合 @function 指令使用,然而功能雖強,卻不常用到。畢竟樣式表的功用主要是描述頁面樣式,而不是提供更多控制。因此在這里不展開研究,感性趣的 戳這里

小結

Sass 完美彌補了上面原生 CSS 暴露的幾個短板,同時新語法 SCSS 使 CSS 開發者可以無縫過渡,是 CSS 預處理器中當之無愧的佼佼者。使用 Sass 容易編寫出結構清晰,可復用,易維護的工程樣式文件,這正是工程化的期望。這么好的東西,速速用起來。

本文主要參考了 Sass 中文網


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM