LESS 提供了多種方式能平滑的將寫好的代碼轉(zhuǎn)化成標(biāo)準(zhǔn) CSS 代碼,在很多流行的框架和工具盒中已經(jīng)能經(jīng)??吹?LESS 的身影了(例如 Twitter 提供的 bootstrap 庫就使用了 LESS)。那么,LESS 是從何而來呢?它和 SASS 等樣式表語言又有何區(qū)別呢?
根據(jù)維基百科上的介紹,其實 LESS 是 Alexis Sellier 受 SASS 的影響創(chuàng)建的開源項目。當(dāng)時 SASS 采用了縮進(jìn)作為分隔符來區(qū)分代碼塊,而不是 CSS 中廣為使用的括號。為了讓 CSS 現(xiàn)有用戶使用起來更為方便,Alexis 開發(fā)了 LESS 并提供了類似的功能。在一開始,LESS 的解釋器也同樣是由 Ruby 編寫,后來才轉(zhuǎn)而采用了 JavaScript. LESS 代碼既可以運行在客戶端,也可以運行在服務(wù)器端。在客戶端只要把 LESS 代碼和相應(yīng)的 JavaScript 解釋器在同一頁面引用即可;而在服務(wù)器端,LESS 可以運行在 Node.js 上,也可以運行在 Rhino 這樣的 JavaScript 引擎上。
說一點題外話,其實現(xiàn)在的 SASS 已經(jīng)有了兩套語法規(guī)則:一個依舊是用縮進(jìn)作為分隔符來區(qū)分代碼塊的;另一套規(guī)則和 CSS 一樣采用了大括弧作為風(fēng)格符。后一種語法規(guī)則又名 SCSS,在 SASS 3 之后的版本都支持這種語法規(guī)則。SCSS 和 LESS 已經(jīng)越來越像了,它倆之間更詳細(xì)的對比可以參考 此鏈接。
我們知道 LESS 擁有四大特性:變量、混入、嵌套、函數(shù)。這些特性在其他文章中已經(jīng)有所介紹,這里就不復(fù)述了。其實,LESS 還擁有一些很有趣的特性有助于我們的開發(fā),例如模式匹配、條件表達(dá)式、命名空間和作用域,以及 JavaScript 賦值等等。讓我們來逐一看看這些特性吧。
相信大家對 LESS 四大特性中的混入 (mixin) 依然印象深刻吧,您用它能夠定義一堆屬性,然后輕松的在多個樣式集中重用。甚至在定義混入時加入?yún)?shù)使得這些屬性根據(jù)調(diào)用的參數(shù)不同而生成不同的屬性。那么,讓我們更進(jìn)一步,來了解一下 LESS 對混入的更高級支持:模式匹配和條件表達(dá)式。
首先,讓我們來回顧一下普通的帶參數(shù)的混入方式:
.border-radius (@radius: 3px) { border-radius: @radius; -moz-border-radius: @radius; -webkit-border-radius: @radius; } .button { .border-radius(6px); } .button2 { .border-radius(); }
.button { border-radius: 6px; -moz-border-radius: 6px; -webkit-border-radius: 6px; } .button2 { border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; }
從上面這個例子可以看出,在混入我們可以定義參數(shù),同時也可以為這個參數(shù)指定一個缺省值。這樣我們在調(diào)用這個混入時如果指定了參數(shù) .border-radius(6px)
,LESS 就會用 6px
來替換,如果不指定參數(shù)來調(diào)用 .border-radius()
,LESS 就會用缺省的 3px
來替換?,F(xiàn)在,我們更近一步,不僅僅通過參數(shù)值來更改最終結(jié)果,而是通過傳入不同的參數(shù)個數(shù)來匹配不同的混入。
.mixin (@a) { color: @a; width: 10px; } .mixin (@a, @b) { color: fade(@a, @b); } .header{ .mixin(red); } .footer{ .mixin(blue, 50%); }
.header { color: #ff0000; width: 10px; } .footer { color: rgba(0, 0, 255, 0.5); }
這個例子有些像 Java 語言中的方法調(diào)用有些類似,LESS 可以根據(jù)調(diào)用參數(shù)的個數(shù)來選擇正確的混入來帶入?,F(xiàn)在,我們了解到通過傳入?yún)?shù)的值,以及傳入不同的參數(shù)個數(shù)能夠選擇不同的混入及改變它的最終代碼。這兩個例子的模式匹配都是非常容易理解的,讓我們換個思路,上面的例子中參數(shù)都是由變量構(gòu)成的,其實在 LESS 中定義參數(shù)是可以用常量的!模式匹配時匹配的方式也會發(fā)生相應(yīng)的變化,讓我們看個實例。
.mixin (dark, @color) { color: darken(@color, 10%); } .mixin (light, @color) { color: lighten(@color, 10%); } .mixin (@zzz, @color) { display: block; weight: @zzz; } .header{ .mixin(dark, red); } .footer{ .mixin(light, blue); } .body{ .mixin(none, blue); }
.header { color: #cc0000; display: block; weight: dark; } .footer { color: #3333ff; display: block; weight: light; } .body { display: block; weight: none; }
通過這個例子我們可以看出,當(dāng)我們定義的是變量參數(shù)時,因為 LESS 中對變量并沒有類型的概念,所以它只會根據(jù)參數(shù)的個數(shù)來選擇相應(yīng)的混入來替換。而定義常量參數(shù)就不同了,這時候不僅參數(shù)的個數(shù)要對應(yīng)的上,而且常量參數(shù)的值和調(diào)用時的值也要一樣才會匹配的上。值得注意的是我們在 body 中的調(diào)用,它調(diào)用時指定的第一個參數(shù) none 并不能匹配上前兩個混入,而第三個混入 .mixin (@zzz, @color)
就不同了,由于它的兩個參數(shù)都是變量,所以它接受任何值,因此它對三個調(diào)用都能匹配成功,因此我們在最終的 CSS 代碼中看到每次調(diào)用的結(jié)果中都包含了第三個混入的屬性。
最后,我們把清單 1 中的代碼做略微改動,增加一個無參的混入和一個常量參數(shù)的混入,您猜猜看最終的匹配結(jié)果會發(fā)生什么變化么?
.border-radius (@radius: 3px) { border-radius: @radius; -moz-border-radius: @radius; -webkit-border-radius: @radius; } .border-radius (7px) { border-radius: 7px; -moz-border-radius: 7px; } .border-radius () { border-radius: 4px; -moz-border-radius: 4px; -webkit-border-radius: 4px; } .button { .border-radius(6px); } .button2 { .border-radius(7px); } .button3{ .border-radius(); }
下面的結(jié)果可能會出乎您的意料,無參的混入是能夠匹配任何調(diào)用,而常量參數(shù)非常嚴(yán)格,必須保證參數(shù)的值 (7px)
和調(diào)用的值 (7px)
一致才會匹配。
.button { border-radius: 6px; -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 4px; -moz-border-radius: 4px; -webkit-border-radius: 4px; } .button2 { border-radius: 7px; -moz-border-radius: 7px; -webkit-border-radius: 7px; border-radius: 7px; -moz-border-radius: 7px; border-radius: 4px; -moz-border-radius: 4px; -webkit-border-radius: 4px; } .button3 { border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 4px; -moz-border-radius: 4px; -webkit-border-radius: 4px; }
有了模式匹配之后是方便了很多,我們能根據(jù)不同的需求來匹配不同的混入,但更進(jìn)一步的就是利用條件表達(dá)式來更加準(zhǔn)確,更加嚴(yán)格的來限制混入的匹配,實現(xiàn)的方式就是利用了 when
這個關(guān)鍵詞。
.mixin (@a) when (@a >= 10) { background-color: black; } .mixin (@a) when (@a < 10) { background-color: white; } .class1 { .mixin(12) } .class2 { .mixin(6) }
.class1 { background-color: black; } .class2 { background-color: white; }
利用 When 以及 <, >, =, <=, >= 是十分簡單和方便的。LESS 并沒有停留在這里,而且提供了很多類型檢查函數(shù)來輔助條件表達(dá)式,例如 iscolor
、isnumber
、isstring
、iskeyword
、isurl
等等。
.mixin (@a) when (iscolor(@a)) { background-color: black; } .mixin (@a) when (isnumber(@a)) { background-color: white; } .class1 { .mixin(red) } .class2 { .mixin(6) }
.class1 { background-color: black; } .class2 { background-color: white; }
另外,LESS 的條件表達(dá)式同樣支持 AND 和 OR 以及 NOT 來組合條件表達(dá)式,這樣可以組織成更為強(qiáng)大的條件表達(dá)式。需要特別指出的一點是,OR 在 LESS 中并不是用 or 關(guān)鍵字,而是用 , 來表示 or 的邏輯關(guān)系。
.smaller (@a, @b) when (@a > @b) { background-color: black; } .math (@a) when (@a > 10) and (@a < 20) { background-color: red; } .math (@a) when (@a < 10),(@a > 20) { background-color: blue; } .math (@a) when not (@a = 10) { background-color: yellow; } .math (@a) when (@a = 10) { background-color: green; } .testSmall {.smaller(30, 10) } .testMath1 {.math(15)} .testMath2 {.math(7)} .testMath3 {.math(10)}
.testSmall { background-color: black; } .testMath1 { background-color: red; background-color: yellow; } .testMath2 { background-color: blue; background-color: yellow; } .testMath3 { background-color: green; }
LESS 所帶來的變量,混入這些特性其實很大程度上避免了傳統(tǒng) CSS 中的大量代碼重復(fù)。變量能夠避免一個屬性多次重復(fù),混入能夠避免屬性集的重復(fù)。而且使用起來更加靈活,維護(hù)起來也方便了許多,只要修改一處定義而無需修改多處引用的地方?,F(xiàn)在,讓我們更進(jìn)一步,當(dāng)我定義好了變量和混入之后,怎么能更好的控制和運用它們呢,怎么避免和其他地方定義的變量及混入沖突?一個顯而易見的想法就是像其他語言一樣引入命名空間和作用域了。首先我們來看一個 LESS 的作用域的例子。
@var: red; #page { @var: white; #header { color: @var; } } #footer { color: @var; }
在這個例子里,可以看到 header 中的 @var
會首先在當(dāng)前作用域?qū)ふ?,然后再逐層往父作用域中尋找,一直到頂層的全局作用域中為止。所?header 的 @var
在父作用域中找到之后就停止了尋找,最終的值為 white。而 footer 中的 @var
在當(dāng)前作用域沒找到定義之后就尋找到了全局作用域,最終的結(jié)果就是全局作用域中的定義值 red。
#page #header { color: #ffffff; // white } #footer { color: #ff0000; // red }
了解了作用域之后讓我們再來看一下命名空間,我們可以用命名空間把變量和混入封裝起來,避免和其他地方的定義沖突,引用起來也十分方便,只要在前面加上相應(yīng)的命名空間就可以了。
@var-color: white; #bundle { @var-color: black; .button () { display: block; border: 1px solid black; background-color: @var-color; } .tab() { color: red } .citation() { color: black} .oops {weight: 10px} } #header { color: @var-color; #bundle > .button; #bundle > .oops;
}
這里可以看出,我們利用嵌套規(guī)則在 #bundle
中建立了一個命名空間,在里面封裝的變量以及屬性集合都不會暴露到外部空間中,例如 .tab(), .citation()
都沒有暴露在最終的 CSS 代碼中。而值得注意的一點是 .oops 卻被暴露在了最終的 CSS 代碼中,這種結(jié)果可能并不是我們想要的。其實同樣的例子我們可以在混入的例子中也可以發(fā)現(xiàn),即無參的混入 .tab()
是和普通的屬性集 .oops
不同的。無參的混入是不會暴露在最終的 CSS 代碼中,而普通的屬性集則會現(xiàn)在出來。我們在定義命名空間和混入時要小心處理這樣的差別,避免帶來潛在的問題。
#bundle .oops { weight: 10px; } #header { color: #ffffff; display: block; border: 1px solid black; background-color: #000000; weight: 10px; }
如果能在 CSS 中使用一些 JavaScript 方法無疑是十分令人興奮的,而 LESS 真正逐步加入這項功能,目前已經(jīng)能使用字符串及數(shù)字的常用函數(shù)了,想要在 LESS 中運用 JavaScript 賦值只需要用反引號(`)來包含所要進(jìn)行的操作即可。讓我們看看實例吧。
.eval { js: `1 + 1`; js: `(1 + 1 == 2 ? true : false)`; js: `"hello".toUpperCase() + '!'`; title: `process.title`; } .scope { @foo: 42; var: `this.foo.toJS()`; } .escape-interpol { @world: "world"; width: ~`"hello" + " " + @{world}`; } .arrays { @ary: 1, 2, 3; @ary2: 1 2 3; ary: `@{ary}.join(', ')`; ary: `@{ary2}.join(', ')`; }
我們可以看到,在 eval 中我們可以用 JavaScript 做數(shù)字運算,布爾表達(dá)式;對字符串做大小寫轉(zhuǎn)化,串聯(lián)字符串等操作。甚至最后能夠獲取到 JavaScript 的運行環(huán)境(process.title
)。同樣可以看到 LESS 的作用域和變量也同樣在 JavaScript 賦值中使用。而最后的例子中,我們看到 JavaScript 賦值同樣運用于數(shù)組操作當(dāng)中。其實 LESS 的 JavaScript 賦值還有支持其他一些方式,不過目前尚未公布出來。
.eval { js: 2; js: true; js: "HELLO!"; title: "/Users/Admin/Downloads/LESS/Less.app/Contents/Resources/engines/bin/node"; } .scope { var: 42; } .escape-interpol { width: hello world; } .arrays { ary: "1, 2, 3"; ary: "1, 2, 3"; }
在 LESS 開發(fā)中,我們可以用 LESS 提供的 JavaScript 腳本來在運行時解析,將 LESS 文件實時翻譯成對應(yīng)的 CSS 語法。如下面這個例子:
<link rel="stylesheet/less" type="text/css" href="helloworld.less"> <script src="less.js" type="text/javascript"></script> <div class="helloworld">Hello World!</div>
從上面的示例可以看出,在 helloworld.less 引入之后我們還添加了一個 JavaScript 文件,這個文件就是 LESS 的解釋器,可以在 LESS 的官方網(wǎng)站上下載此文件。需要注意的是,要注意 LESS 文件和 LESS 解釋器的引入順序,確保所有的 LESS 文件都在 LESS 解釋器之前。
看到這里也許有人會說,實時解析的話方便倒是方便,可以性能上不就有損耗了么?比起普通 CSS 來說多了一道解釋的手續(xù)。也許還有的人對寫好的 LESS 文件不太放心,希望能看到解析之后的 CSS 文件來檢查下是否是自己希望的內(nèi)容。這兩個問題其實都是能夠解決的,LESS 提供了服務(wù)端的方案,使用 npm 安裝 LESS 之后就能夠?qū)⒛械?LESS 文件批量轉(zhuǎn)化成 CSS 文件,然后您拿到 CSS 文件就可以隨心所欲了,檢查生成的內(nèi)容是否有誤,也可以直接在 HTML 中引用,再也不用添加 LESS 的 JavaScript 文件來解析它了。關(guān)于這部分的詳細(xì)安裝信息,可以直接參考 LESS 官網(wǎng)上的介紹,這里就不復(fù)述了。
不過,對于 Mac 用戶來說還有一個更方便的工具可以使用,它就是 less.app. 這是一個第三方提供的工具,使用起來十分方便,我們可以在下圖所示的界面上添加 LESS 文件所在的目錄,此工具就會在右側(cè)列出目錄中包含的所有 LESS 文件。最酷的是,從此您就不用再操心惦記著要把 LESS 文件編譯成 CSS 文件了,這個工具會在您每次修改完保存 LESS 文件時自己執(zhí)行編譯,自動生成 CSS 文件。這樣,您就可以隨時查看 LESS 代碼的最終效果,檢查目標(biāo) CSS 是否符合您的需要了,實在是太方便了!
更值為稱道的是,LESS.app 還是個免費軟件,接受捐贈:)
通過上面的簡單介紹,希望大家了解到了 LESS 的主要功能,相信 LESS 會讓前端攻城師的工作更為輕松,更加靈活。更多的細(xì)節(jié)可以參考 LESS 官方網(wǎng)站。
聯(lián)系客服