CSS預處理器Sass(Scss)、Less、Stylus

         CSS 預處理編譯器能讓我成程序化其的方式編寫CSS代碼,能夠引入CSS中沒有的變量、條件、函數等特性,從而讓代碼更簡單易維護,但通常按預處理器語法編寫的代碼沒法直接在瀏覽器中運行,需用經過工具好比gulp轉換成標準的CSS語法,從而在瀏覽器中運行。我的理解它是標準CSS語法的擴展及加強,能在必定程度上提升編碼效率。
三種預處理器的對比:
Sass誕生是最先也是最成熟的CSS預處理器,有Ruby社區和Compass支持;安裝、編譯依賴Ruby環境;
Stylus早期服務器Node JS項目,在該社區獲得必定支持者, 安裝、編譯依賴NodeJs環境
LESS出現於2009年,支持者遠超於Ruby和Node JS社區 安裝、編譯依賴NodeJs環境 ,表明bootstrap;
Sass和LESS語法較爲嚴謹、嚴密,而Stylus語法相對散漫(借鑑python),其中LESS學習起來更快一些,由於他更像CSS的標準;
Sass和LESS相互影響較大,其中Sass受LESS影響,已經進化到了全面兼容CSS的SCSS;
Sass和LESS都有第三方工具提供轉譯,特別是Sass和Compass是絕配;
Sass、LESS和Stylus都具備變量、做用域、混合、嵌套、繼承、運算符、顏色函數、導入和註釋等基本特性,並且以「變量」、「混合」、「嵌套」、「繼承」和「顏色函數」稱爲五大基本特性,各自特性實現功能基本類似,只是使用規則上有所不一樣;
Sass和Stylus具備相似於語言處理的能力,好比說條件語句、循環語句等,而LESS須要經過When等關鍵詞模擬這些功能,在這一方面略遜一層;
最後摘錄一下爲何要用CSS預處理器

1# CSS沒法遞歸式定義

CSS語法不支持遞歸定義的表達式,因此你沒有辦法用一個語句定義一個啓發式的規則。css

好比這樣的需求:「.w後面跟着一個數字,這個數字表明着width爲百分之多少」(bootstrap的柵格系統就包含12種相對父級寬度的類定義)。
儘管徹底是一個規則裏定義出的,但你只能這樣寫CSS:python

.w1 { width: 1% }
.w2 { width: 2% }
/** .w3 ... ... .w99 **/.w100 { width: 100% }

這樣將形成很大的冗餘,修改費時費力。但若是預編譯CSS,就很是簡單了:web

@maxnumber : 100 ;
.makeWidthRules(@number) when(@number <= @maxnumber ){
  .w@{number}{ width: 1% * @number ;
  }
  .makeWidthRules(@number + 1) ;
}
.makeWidthRules(1) ;

2# CSS的mixin式複用性支持不夠

使用純CSS,咱們能夠抽象出一些經常使用的佈局CSS屬性組合,經過CSS的類組合來達成常見的mixin式複用。
好比這樣:chrome

<style>.tc { text-align: center; }.m { margin-left: auto; margin-right: auto; }.w50p { width: 50%; }.db { display: block; }</style><div class="tc m w50p"><img class="db"></div>

這種方案有幾個問題:gulp

  • 頁面重構時,須要頻繁修改class name;
    這個問題在後端人員掌握着視圖層的時候格外突出,先後端耗費不少溝通成本。
  • 要約束上下文的時候很是無力
    好比「只有在ul下面的img.db容許是display:block」的規則,寫成ul img.db { display: block; }就徹底跑偏了——它違背了你建立這個.db類時的本意,形成了代碼的可讀性和可維護性降低。若是你要改動規則,須要同時修改HTML和CSS,也可能形成新的樣式問題。

若是咱們想要創建一種代碼風格,只容許CSS Class表明UI模塊的抽象——改動樣式時不至於通知後端改模板——咱們就要將上面這個例子的tc m w50p換用一個有實際語義的類名如headwrap,而後在CSS內部實現mixin。
——而這正是CSS的短板,CSS體系內的用法只有複製粘貼。bootstrap

至於如何用預編譯語言作mixin,一個很是好的SASS示例由 @nightire 在這個回答裏給出,容我摘錄一小段:segmentfault

.btn-standout {
    @extend .btn;
    @extend .btn-block;

    @media (max-width: $screen-xs-max) {
        @include button-size(
            $padding-large-vertical,
            $padding-large-horizontal,
            $font-size-large,
            $line-height-large,
            $border-radius-large
        );
    }

    &.sell {
        @extend .btn-primary;
    }
}

3# 預編譯可緩解多瀏覽器兼容形成的冗餘

進入CSS3的時代,舊式CSS hack如filter,新式兼容前綴如-webkit-等,都是冗餘,修改的時候也須要修改多處,不容易維護。後端

好比對rgba背景的兼容:瀏覽器

.bg { filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#ccff825b,endcolorstr=#ccff825b); }:root .bg { -ms-filter: none; background: rgba(255,130,91,0.8) }

在LESS裏面,寫個函數就能解決,屢次複用也不須要看到如此之多的hack:ruby

.rgbaBG(@c , @a){
    @rgba : rgba(red(@c),green(@c),blue(@c),@a);
    @shim : argb(@rgba) ;
    filter: ~"progid:DXImageTransform.Microsoft.gradient(startcolorstr=@{shim},endcolorstr=@{shim})" ;
    :root & {
        -ms-filter: none ;
        background: @rgba ;
    }
}
.bg {
    .rgbaBG(#ff825b, 0.8) ;
}

此外,使用LESS時,能夠很方便地使用base64 data uri的方案。不須要直接面臨在CSS中一大坨字符:

.bg { background: data-uri('../data/image.jpg'); }

SASS的相似方案見評論。

N# 預編譯不是萬金油

預編譯不是萬金油,CSS的好處在於簡便、隨時隨地被使用和調試。預編譯CSS步驟的加入,讓咱們開發工做流中多了一個環節,調試也變得更麻煩了。

舉個例子:原先咱們只須要在chrome/firebug裏面找到相應的選擇器,如.popup .popup-wrap .head,源文件裏面ctrl+F查找.popup .popup-wrap .head就能夠快速定位語句。如今咱們沒法直接在預編譯文件中查找,而須要尋找上下文,由於它在LESS中一般是這樣被定義的:

.popup {
    .popup-wrap {
        .head { }
    }
}

更大的問題在於,預編譯很容易形成後代選擇器的濫用。
曾經有一個觀點是預編譯能夠解決樣式覆寫的問題,而我以爲,正是預編譯語言模糊了樣式覆寫的問題,而致使要解決樣式相互覆寫的問題時,問題已經變得規模龐大而難以解決。

舉個極端的例子:

.popup {
    font-size: 12px;
    a { font-size: 13px; }
    .head { font-size: 18px; }
}
.informative {
    font-size: 14px;
    .head { font-size: 16px; }
}

若是我有這麼一個文檔結構.popup.informative > .head > a,須要afont-size17px,你能快速想明白怎麼改嗎?疊羅漢式地再疊一層?仍是再糊一層牆皮,加一行樣式?仍是乾脆用!important轟炸一番?

所以,實際項目中衡量預編譯方案時,仍是得想一想,比起帶來的額外維護開銷,預編譯有沒有解決更大的麻煩。


 


相關文章
相關標籤/搜索