在寫CSS的時候我們會發現,為了兼容瀏覽器等原因,我們往往需要寫很多冗余的代碼,CSS預處理器就是為了解決CSS的這些問題,簡化CSS代碼的編寫。
目前最主流的CSS預處理器是LESS、SASS和Stylus,最近花了幾天時間學習并使用了它們,于是就想對這三個預處理器做個比較。根據這三種語言的特性,主要從一下幾個方面進行討論:
- 基本語法
- 變量
- 嵌套
- 混入(mixin)
- 繼承
- 函數
- @import
- 運算符
- 邏輯控制
基本語法
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預處理器還需要自己斟酌,多踩坑才能體會到哪種預處理器最適合你當前的項目。