1. 程式人生 > >為什麼要使用CSS預編譯處理器?eg:LESS,SASS

為什麼要使用CSS預編譯處理器?eg:LESS,SASS

前端逐步瞭解的過程中,經常提及一個技術:css預編譯處理

查詢相關資料後發現,是用另一種格式的語言讓css也能像程式語言一樣寫,然後再將其轉換為css

瞭解其大概原理後,就十分疑惑為什麼要引進這種技術與概念,查詢相關資料後,發現有個帖子解答了我的疑惑:

感覺答主寫得很好

1# CSS無法遞迴式定義

CSS語法不支援遞迴定義的表示式,所以你沒有辦法用一個語句定義一個啟發式的規則。

比如這樣的需求:“.w後面跟著一個數字,這個數字代表著width為百分之多少”(bootstrap的柵格系統就包含12種相對父級寬度的類定義)。 儘管完全是一個規則裡定義出的,但你只能這樣寫CSS:

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

這樣將造成很大的冗餘,修改費時費力。但如果預編譯CSS,就非常簡單了:

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

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

使用純CSS,我們可以抽象出一些常用的佈局CSS屬性組合,通過CSS的類組合來達成常見的mixin式複用。 比如這樣:

<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>

這種方案有幾個問題:

  • 頁面重構時,需要頻繁修改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體系內的用法只有複製貼上。

至於如何用預編譯語言做mixin,一個非常好的SASS示例由 @nightire 在這個回答裡給出,容我摘錄一小段:

.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:

.rgbaBG(@c , @a){
    @rgba : rgba(red(@c),green(@c),blue(@c),@a);
    @shim : argb(@rgba) ;
    filter: ~"progid:DXImageTransform.Microsoft.gradient([email protected]{shim},[email protected]{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轟炸一番?

因此,實際專案中衡量預編譯方案時,還是得想想,比起帶來的額外維護開銷,預編譯有沒有解決更大的麻煩。