談談CSS預處理器

在寫CSS的時候咱們會發現,爲了兼容瀏覽器等緣由,咱們每每須要寫不少冗餘的代碼,CSS預處理器就是爲了解決CSS的這些問題,簡化CSS代碼的編寫。php

目前最主流的CSS預處理器是LESS、SASS和Stylus,最近花了幾天時間學習並使用了它們,因而就想對這三個預處理器作個比較。根據這三種語言的特性,主要從一下幾個方面進行討論:css

  1. 基本語法web

  2. 變量編程

  3. 嵌套瀏覽器

  4. 混入(mixin)sass

  5. 繼承less

  6. 函數編程語言

  7. @import函數

  8. 運算符學習

  9. 邏輯控制

基本語法

LESS的基本語法和CSS差很少,SASS和Stylus均可以利用縮進代替花括號,而且空格有重要的意義。SASS保存爲".sass"是縮進格式,保存爲".scss"是非縮進格式。SASS通常使用".scss"擴展名。LESS的擴展名爲".less",Stylus的擴展名爲".styl"。

注意:SASS依賴於Ruby,安裝前必須先安裝Ruby。

LESS & SCSS:

ul {
    list-style: none;
}

SASS:

ul
    list-style: none

Stylus:

ul
    list-style none

注意:如下SASS代碼都以擴展名爲".scss"的方式書寫。

變量

CSS預處理器中能夠定義變量,而且能夠在樣式表中使用,變量類型沒有限制,這樣就能夠必定程度上減小CSS中沒法避免的重複問題。

LESS變量名必須以@符號開頭,變量名和變量值之間以冒號隔開。有個問題是@規則在CSS中算是一種原生的擴展方式,變量名用@開頭極可能會和之後CSS中的新@規則衝突。

@orange: #feb914;
header {
    background-color: @orange;
}

SASS變量名必須以$開始,變量名和變量值之間以冒號隔開。

$orange: #feb914;
header {
    background-color: $orange;
}

Stylus對變量名沒有任何限定,變量名與變量值之間能夠用冒號、空格和等號隔開。

bgorange = #feb914;
header
    background-color bgorange

上面三種不一樣的寫法都會產生相同的結果:

header {
    background-color: #feb914;
}

Stylus還有一個獨特功能,它不須要分配值給變量就能夠定義引用屬性。以下:

#logo
    position: absolute
    top: 50%
    left: 50%
    width: w = 150px
    height: h = 80px
    margin-left: -(w / 2)
    margin-top: -(h / 2)
#logo
    position: absolute
    top: 50%
    left: 50%
    width: 150px
    height: 80px
    margin-left: -(@width / 2)
    margin-top: -(@height / 2)

變量做用域

三種預處理器中定義的變量都是有做用域的,查找變量的順序是先在局部定義中查找,若是找不到,則逐級向上查找。

若是咱們在代碼中重寫某個已經定義的變量,Less的處理邏輯和其餘兩個有區別。Less中,這個行爲叫懶加載(Lazy Loading)。注意Less中全部變量的計算,都是以這個變量最後一次被定義的值爲準。

LESS:

@size: 40px;
.content {
    width: @size;
}
@size: 60px;
.container {
    width: @size;
}

編譯輸出爲:

.content {
    width: 60px;
}
.container {
    width: 60px;
}

在SASS中狀況以下:

$size: 40px;
.content {
    width: $size;
}
$size: 60px;
.container {
    width: $size;
}

編譯輸出爲:

.content {
    width: 40px;
}
.container {
    width: 60px;
}

Stylus和SASS行爲相同,變量的計算以變量最近一次的定義爲準。

變量插值

預處理器中定義的變量不只能夠用做屬性值,還能夠用做選擇器,屬性名等,這就是變量插值。

變量名插值

Less中支持以@@var的形式引用變量,即該變量的名字是由@var的值決定的。

選擇器插值

以類選擇器爲例

LESS:

@way: new;
.@{way}-task {
    font-size: 18px;
}

SASS:

$way: new;
.#{$way}-task {
    font-size: 18px;
}

Stylus:

way: new;
.{way}-task
    font-size 18px

解析結果都是:

.new-task {
    font-size: 18px;
}

注意:在Less中,經過選擇器插值生成的規則沒法被繼承。

@import插值

Sass中只能在使用url()表達式時進行變量@import插值:

$device: mobile;
@import url(styles.#{$device}.css);

Less中能夠在字符串中進行插值:

@device: mobile;
@import "styles.@{device}.css";

Stylus中沒有@import插值,可是能夠利用其字符串拼接的功能實現:

device = "mobile"
@import "styles." + device + ".css"

屬性名插值

三個預處理器均支持屬性名插值,使用方式且和上述插值相似。

嵌套

若是須要在相同的父元素中選擇多個子元素,須要一遍又一遍地寫父元素,若是用CSS預處理器就能夠不用重複寫父元素,而且父元素和子元素的關係一目瞭然。

三種預處理器的嵌套語法是一致的,引用父級選擇器的標記&也相同。除了&,Sass和Stylus還分別用@at -root和"/"符號做爲嵌套時根規則集的選擇器引用。首先以LESS爲例討論嵌套語法:

#sort {
    margin-top: 24px;
    ul {
        margin-left: 8px;
        line-height: 36px;
        vertical-align: middle;    
    }
}
input {
    width: 80px;
    &:-ms-input-placeholder {
    font-size: 16px;
    color: @white;
    }
}

編譯結果爲:

#sort {
    margin-top: 24px;
}
#sort ul {
    margin-left: 8px;
    line-height: 36px;
    vertical-align: middle;
}
input {
    width: 80px;
}
input:-ms-input-placeholder {
    font-size: 16px;
    color: @white;
}

SASS還提出了屬性嵌套,屬性嵌套指的是有些屬性擁有相同的開始單詞,如border-width,border-color都是以border開頭。官網的實例以下:

.fakeshadow {
    border: {
        style: solid;
        left: {
            width: 4px;
            color: #888;
        }
        right: {
            width: 2px;
            color: #ccc;
        }
    }
}

生成的CSS爲:

.fakeshadow {
    border-style: solid;
    border-left-width: 4px;
    border-left-color: #888;
    border-right-width: 2px;
    border-right-color: #ccc; 
}

混入(mixin)

mixins有點像C語言中的宏,當某段CSS常常須要在多個元素中使用時,能夠爲這些共用的CSS定義一個mixin,而後只須要在須要引用這些CSS地方調用該mixin便可。

三種預處理器的mixin使用方式的差別比較大,下面分別說明。

LESS混入方式以下:

.my-mixin {
    color: black;
}
.my-other-mixin() {
    background: white;
}
.my-hover-mixin() {
    &:hover {
        border: 1px solid red;
  }
}
.border-radius(@radius: 5px) {
    -webkit-border-radius: @radius;
        -moz-border-radius: @radius;
            border-radius: @radius;
}
.class {
    .my-mixin;
    .my-other-mixin;
}
button {
    .my-hover-mixin();
}
#header {
    .border-radius(4px);
}
.button {
    .border-radius;
}

編譯輸出爲:

.my-mixin {
    color: black;
}
.class {
    color: black;
    background: white;
}
button:hover {
    border: 1px solid red;
}
#header {
    -webkit-border-radius: 4px;
        -moz-border-radius: 4px;
            border-radius: 4px;    
}
.button {
    -webkit-border-radius: 5px;
        -moz-border-radius: 5px;
            border-radius: 5px;    
}

LESS的mixin須要注意的是同名的mixin不是後面的覆蓋前面的,而是會累加輸出。這就會產生一個問題,若是存在和mixin同名的class樣式,而且mixin沒有參數,則在調用時會把對應的class樣式一塊兒輸出,這顯然不是咱們所須要的。

SASS的mixin用法以下:

@mixin center-block {
    margin-left:auto;
    margin-right:auto;
}
.demo{
    @include center-block;
}
@mixin horizontal-line($border:1px dashed #ccc, $padding:10px){
    border-bottom:$border;
    padding-top:$padding;
    padding-bottom:$padding;  
}
.imgtext-h li{
    @include horizontal-line(1px solid #ccc);
}

編譯結果爲:

.demo{
    margin-left:auto;
    margin-right:auto;
}
.imgtext-h li {
    border-bottom: 1px solid #cccccc;
    padding-top: 10px;
    padding-bottom: 10px;
}

Sass用@mixin和@include兩個指令清楚地說明了mixin的定義和引用方式。

Stylus的mixin和Sass的相似:

border-radius(n)
    -webkit-border-radius n
    -moz-border-radius n
    border-radius n
form input[type=button]
    border-radius 5px

繼承

繼承其實和混入的做用差很少,那爲何還須要繼承呢?混入確實很好用,可是若是多個地方都混入一樣的代碼,會形成代碼的重複。例如:

.block {
    margin: 10px 5px;
    padding: 2px;
}
p {
    .block; 
    border: 1px solid #EEE;
}

會輸出:

.block {
    margin: 10px 5px;
    padding: 2px;
}
p {
    margin: 10px 5px;
    padding: 2px; 
    border: 1px solid #EEE;
}

而咱們指望的輸出實際是:

.block,
p {
    margin: 10px 5px;
    padding: 2px;
}
p {
    border: 1px solid #EEE;
}

用繼承就能夠實現上面的輸出,不會有重複的代碼(以SASS爲例):

.block {
    margin: 10px 5px;
    padding: 2px;
}
p {
    @extend .block; 
    border: 1px solid #EEE;
}

Stylus的繼承來源於SASS,二者使用方式相同。而LESS則用僞類來實現繼承:

.block {
    margin: 10px 5px;
    padding: 2px;
}
p {
    &:extend(.block); 
    border: 1px solid #EEE;
}

Less默認只繼承父類自己的樣式,若是要同時繼承嵌套定義在父類做用域下的樣式,得使用關鍵字all,好比&:extend(.block all)。

函數

三種預處理器都有本身的內置函數,例如顏色處理,類型判斷等。LESS中不能自定義函數,SASS和Stylus能夠。

SASS自定義函數用法以下,須要使用@function,並用@return指令返回結果:

@function pxToRem($px) {
    @return $px / 2;
}

body{
    font-size: pxToRem(32px);
}

Stylus中則無需這些指令:

pxToRem(n)
    n / 2
body
    font-size: pxToRem(32px)

@import

@import的做用是從其餘樣式表導入樣式,三種預處理器的@import的使用方式各不相同。

除了基本的功能外,LESS引入了import選項來擴展@import的語法。語法以下:

@import (keyword) "filename";

其中keyword能夠是以下幾種選項(能夠聯合使用)。
1.reference:使用一個外部文件參與編譯,但不輸出其內容。
2.inline:直接將引入的文件放入輸出文件中,但不處理這個引入的文件。
3.less:無論文件擴展名是什麼都將該文件做爲一個LESS文件處理。
4.css:無論文件擴展名是什麼都將該文件做爲一個CSS文件處理。
5.once:只引入文件一次(去重),這是默認方式。
6.multiple:能夠引入文件屢次。

SASS則沒有LESS的這些擴展語法,它本身推斷引入的方式。它的@import 不會被去重,屢次引入會致使一個樣式文件被屢次輸出到編譯結果中。

Stylus的@import和SASS同樣都是本身推斷引入的方式,可是Stylus能夠進行引入文件的去重,它有一個自定義的指令@require,用法和@import同樣,但引入的文件只會編譯一次。

運算符

三種預處理器都具備運算的特性,能夠對數值型的Value(如:數字、顏色、變量等)進行加減乘除四則運算。
Stylus的中文文檔中,詳細討論了Stylus的運算符

邏輯控制

Sass中經過@iF 、@else 實現條件判斷來提供語言的流控制,經過@for、@each、@while實現循環,而後配合map和list這兩種數據類型能夠實現多數編程語言提供的功能。
SASS中還實現了一個三目判斷,語法爲:if($condition, $if_true, $if_false) 。三個參數分別表示:條件,條件爲真的值,條件爲假的值。

Stylus中經過if、else if、else、unless(基本與if相反)實現條件判斷來提供語言的流控制,經過for/in實現循環迭代。

而LESS中沒有上述複雜的語法,只經過guarded mixins代替if/else實現簡單的條件判斷。舉例以下:

.mixin (@a) when (lightness(@a) >= 50%) {
    background-color: black;
}
.mixin (@a) when (lightness(@a) < 50%) {
    background-color: white;
}
.mixin (@a) {
    color: @a;
}

以上就是三種CSS預處理器的主要區別,實際項目中使用哪一種CSS預處理器還須要本身斟酌,多踩坑才能體會到哪一種預處理器最適合你當前的項目。

相關文章
相關標籤/搜索