作爲CSS的一種擴展,LESSCSS不僅向下兼容CSS的語法,而且連新增的特性也是使用CSS的語法。這樣的設計使得學習LESS很輕鬆,而且你可以在任何時候回退到CSS。
變量
很容易理解:
@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;
#header { color: @light-blue; }
輸出:
#header { color: #6c94be; }
甚至可以在定義變量值時使用其它的變量:
@fnord: "I am fnord.";
@var: 'fnord';
content: @@var;
解析後:
content: "I am fnord.";
如果對同一個變量定義兩次的話,在當前作用域中最後一次定義的將被使用。這與CSS的機制類似,最後一次定義的值會成爲這個屬性的值。
比如:
@var: 0;
.class1 {
@var: 1;
.class {
@var: 2;
three: @var;
@var: 3;
}
one: @var;
}
會編譯成:
.class1 .class {
three: 3;
}
.class1 {
one: 1;
}
變量是“按需加載”(lazy loaded)的,因此不必強制在使用之前聲明。
下面是一個有效的LESS代碼片段:
lazy-eval {
width: @var;
}
@var: @a;
@a: 9%;
下面這個片段也是有效的:
.lazy-eval-scope {
width: @var;
@a: 9%;
}
@var: @a;
@a: 100%;
這兩個片段都會編譯成:
.lazy-eval-scope {
width: 9%;
}
混合(Mixins)
在 LESS 中我們可以定義一些通用的屬性集爲一個 class,然後在另一個 class 中去調用這些屬性,下面有這樣一個 class:
.bordered {
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
那如果我們現在需要在其他 class 中引入那些通用的屬性集,那麼我們只需要在任何 class 中像下面這樣調用就可以了:
#menu a {
color: #111;
.bordered;
}
.post a {
color: red;
.bordered;
}
.bordered
class 裏面的屬性樣式都會在 #menu
a
和 .post a
中體現出來:
#menu a {
color: #111;
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
.post a {
color: red;
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
任何 CSS class, id 屬性集都可以以同樣的方式引入。
注意:變量也會被混合,也就是說變量會被帶到當前的作用域。這個特性還有爭議,也許在未來會有變化。
帶參數混合
在 LESS 中,你還可以像函數一樣定義一個帶參數的屬性集合:
.border-radius (@radius) {
border-radius: @radius;
-moz-border-radius: @radius;
-webkit-border-radius: @radius;
}
然後在其他 class 中像這樣調用它:
#header {
.border-radius(4px);
}
.button {
.border-radius(6px);
}
我們還可以像這樣給參數設置默認值:
.border-radius (@radius: 5px) {
border-radius: @radius;
-moz-border-radius: @radius;
-webkit-border-radius: @radius;
}
所以現在如果我們像這樣調用它的話:
#header {
.border-radius;
}
radius
的值就會是 5px。
你也可以定義不帶參數屬性集合,如果你想隱藏這個屬性集合,不讓它暴露到 CSS 中去,但是你還想在其他的屬性集合中引用,你會發現這個方法非常的好用:
.wrap () {
text-wrap: wrap;
white-space: pre-wrap;
white-space: -moz-pre-wrap;
word-wrap: break-word;
}
pre { .wrap }
輸出:
pre {
text-wrap: wrap;
white-space: pre-wrap;
white-space: -moz-pre-wrap;
word-wrap: break-word;
}
多參數混合
多個參數可以使用分號或者逗號分隔,推薦使用分號分隔,因爲逗號有兩重含義:它既可以表示混合的參數,也可以表示一個參數中一組值的分隔符。
使用分號作爲參數分隔符意味着可以將逗號分隔的一組值作爲一個變量處理。換句話說,如果編譯器在混合的定義或者是調用中找到至少一個分號,就會假設參數是使用分號分隔的,所有的逗號都屬於參數中的一組值的分隔符。
2個參數,每個參數都含有通過逗號分隔的一組值的情況:.name(1, 2, 3;
something, else)
。
3個參數,每個參數只含一個數字的情況:.name(1, 2, 3)
。
使用一個象徵性的分號可以創建一個只含一個參數,但參數包含一組值的混合:.name(1, 2, 3;)
。
逗號分隔的一組值參數的默認值:.name(@param1: red, blue;)
。
使用同樣的名字和同樣數量的參數定義多個混合是合法的。在被調用時,LESS會應用到所有可以應用的混合上。比如你調用混合時只傳了一個參數.mixin(green)
,那麼所有隻強制要求一個參數的混合都會被調用:
.mixin(@color) {
color-1: @color;
}
.mixin(@color; @padding:2) {
color-2: @color;
padding-2: @padding;
}
.mixin(@color; @padding; @margin: 2) {
color-3: @color;
padding-3: @padding;
margin: @margin @margin @margin @margin;
}
.some .selector div {
.mixin(#008000);
}
編譯結果:
.some .selector div {
color-1: #008000;
color-2: #008000;
padding-2: 2;
}
@arguments 變量
@arguments包含了所有傳遞進來的參數。 如果你不想單獨處理每一個參數的話就可以像這樣寫:
.box-shadow (@x: 0, @y: 0, @blur: 1px, @color: #000) {
box-shadow: @arguments;
-moz-box-shadow: @arguments;
-webkit-box-shadow: @arguments;
}
.box-shadow(2px, 5px);
將會輸出:
box-shadow: 2px 5px 1px #000;
-moz-box-shadow: 2px 5px 1px #000;
-webkit-box-shadow: 2px 5px 1px #000;
高級參數用法與 @rest
變量
如果需要在 mixin 中不限制參數的數量,可以在變量名後添加 ...,表示這裏可以使用 N 個參數。
.mixin (...) { // 接受 0-N 個參數
.mixin () { // 不接受任何參數
.mixin (@a: 1) { // 接受 0-1 個參數
.mixin (@a: 1, ...) { // 接受 0-N 個參數
.mixin (@a, ...) { // 接受 1-N 個參數
此外:
.mixin (@a, @rest...) {
// @rest 表示 @a 之後的參數
// @arguments 表示所有參數
}
!important
關鍵字
調用時在混合後面加上!important
關鍵字表示將混合帶來的所有屬性標記爲!important
:
.mixin (@a: 0) {
border: @a;
boxer: @a;
}
.unimportant {
.mixin(1);
}
.important {
.mixin(2) !important;
}
編譯成:
.unimportant {
border: 1;
boxer: 1;
}
.important {
border: 2 !important;
boxer: 2 !important;
}
模式匹配與Guard表達式
LESS 提供了通過參數值控制 mixin 行爲的功能,讓我們先從最簡單的例子開始:
.mixin (@s, @color) { ... }
.class {
.mixin(@switch, #888);
}
如果要根據 @switch
的值控制 .mixin
行爲,只需按照下面的方法定義 .mixin
:
.mixin (dark, @color) {
color: darken(@color, 10%);
}
.mixin (light, @color) {
color: lighten(@color, 10%);
}
.mixin (@_, @color) {
display: block;
}
然後調用:
@switch: light;
.class {
.mixin(@switch, #888);
}
將會得到以下 CSS:
.class {
color: #a2a2a2;
display: block;
}
傳給 .mixin
的顏色將執行 lighten
函數,如果 @switch
的值是 dark
,那麼則會執行 darken
函數輸出顏色。
以下是整個過程如何發生的:
- 第一個
.mixin
沒有匹配,因爲不滿足dark
條件; - 第二個
.mixin
可以被匹配,因爲它滿足了light
條件; - 第三個
.mixin
也可以被匹配,因爲它接受任何參數。
只有滿足匹配要求的混合纔會被使用。混合中的變量可以匹配任何值,非變量形式的值只有與傳入的值完全相等時纔可以匹配成功。
我們也可以根據參數的數量進行匹配,比如:
.mixin (@a) {
color: @a;
}
.mixin (@a, @b) {
color: fade(@a, @b);
}
調用 .mixin
時,如果使用了一個參數,輸出第一個 .mixin
,使用了兩個參數,則輸出第二個。
Guards
與上面匹配值或者匹配參數數量的情況不同,Guards 被用來匹配表達式 (expressions)。如果你很熟悉編程函數的用法,那麼很可能你已經掌握它的用法了。
爲了儘可能地符合 CSS 的語言結構,LESS 選擇使用 guard混合(guarded mixins)(類似於 @media
的工作方式)執行條件判斷,而不是加入 if/else
聲明。
首先通過下面的例子開始介紹:
.mixin (@a) when (lightness(@a) >= 50%) {
background-color: black;
}
.mixin (@a) when (lightness(@a) < 50%) {
background-color: white;
}
.mixin (@a) {
color: @a;
}
要點在於關鍵詞 when
,它引入了一個 guard 條件 (這裏只用到一個 guard)。現在如果運行下面的代碼:
.class1 { .mixin(#ddd) }
.class2 { .mixin(#555) }
將會得到以下輸出結果:
.class1 {
background-color: black;
color: #ddd;
}
.class2 {
background-color: white;
color: #555;
}
Guards 支持的運算符包括:>
>=
=
=<
<
。說明一下,true
關鍵字是唯一被判斷爲真的值,也就是這兩個混合是相等的:
.truth (@a) when (@a) { ... }
.truth (@a) when (@a = true) { ... }
其他不爲 true
的值都判爲假:
.class {
.truth(40); // 不會匹配上面的 mixin
}
多個Guards可以通過逗號表示分隔,如果其中任意一個結果爲 true
,則匹配成功:
.mixin (@a) when (@a > 10), (@a < -10) { ... }
值得注意的是不同的參數之間也可以比較,而參與比較的也可以一個參數都沒有:
@media: mobile;
.mixin (@a) when (@media = mobile) { ... }
.mixin (@a) when (@media = desktop) { ... }
.max (@a, @b) when (@a > @b) { width: @a }
.max (@a, @b) when (@a < @b) { width: @b }
如果需要根據值的類型匹配混合,可以使用 is*
函數:
.mixin (@a, @b: 0) when (isnumber(@b)) { ... }
.mixin (@a, @b: black) when (iscolor(@b)) { ... }
幾個檢查基本類型的函數:
iscolor
isnumber
isstring
iskeyword
isurl
如果需要檢查一個值(數字)使用了哪個單位,可以使用下面三個函數:
ispixel
ispercentage
isem
最後,你可以使用關鍵詞 and
在 guard
中加入額外的條件:
.mixin (@a) when (isnumber(@a)) and (@a > 0) { ... }
或者,使用關鍵詞 not
否定條件:
.mixin (@b) when not (@b > 0) { ... }
嵌套規則
LESS 可以讓我們以嵌套的方式編寫層疊樣式。 讓我們先看下下面這段 CSS:
#header { color: black; }
#header .navigation {
font-size: 12px;
}
#header .logo {
width: 300px;
}
#header .logo:hover {
text-decoration: none;
}
在 LESS 中, 我們就可以這樣寫:
#header {
color: black;
.navigation {
font-size: 12px;
}
.logo {
width: 300px;
&:hover { text-decoration: none }
}
}
或者這樣寫:
#header { color: black;
.navigation { font-size: 12px }
.logo { width: 300px;
&:hover { text-decoration: none }
}
}
代碼更簡潔了,而且感覺跟 DOM 結構格式有點像。
注意 &
符號的使用 — 如果你想寫串聯選擇器,而不是寫後代選擇器,就可以用到 &
了。這點對僞類尤其有用如:hover
和 :focus
。
例如:
.bordered {
&.float {
float: left;
}
.top {
margin: 5px;
}
}
會輸出:
.bordered.float {
float: left;
}
.bordered .top {
margin: 5px;
}
嵌套 Media Queries
Media query也可以使用同樣的方式進行嵌套。
.one {
@media (width: 400px) {
font-size: 1.2em;
@media print and color {
color: blue;
}
}
}
輸出:
@media (width: 400px) {
.one {
font-size: 1.2em;
}
}
@media (width: 400px) and print and color {
.one {
color: blue;
}
}
&
的高級用法
用在選擇器中的&
還可以反轉嵌套的順序並且可以應用到多個類名上。
例如:
.child, .sibling {
.parent & {
color: black;
}
& + & {
color: red;
}
}
輸出:
.parent .child,
.parent .sibling {
color: black;
}
.child + .child,
.child + .sibling,
.sibling + .child,
.sibling + .sibling {
color: red;
}
&
也可以用在混合中用於指示嵌套這個混合的父選擇器。
運算
任何數字、顏色或者變量都可以參與運算,運算應該被包裹在括號中。來看一組例子:
@base: 5%;
@filler: (@base * 2);
@other: (@base + @filler);
color: (#888 / 4);
background-color: (@base-color + #111);
height: (100% / 2 + @filler);
LESS 的運算已經超出了我們的期望,如果像下面這樣的話,它能夠分辨出顏色和單位:
@var: (1px + 5);
LESS 將會使用出現的單位,最終輸出 6px
。
也可以使用括號:
width: ((@var + 5) * 2);
函數
LESS 提供了多種函數用於控制顏色變化、處理字符串、算術運算等等。這些函數在函數手冊中有詳細介紹。
函數的用法非常簡單,下面這個例子將介紹如何將 0.5
轉換爲 50%
,將顏色飽和度增加 5%
,以及顏色亮度降低25%
色相值增加 8
等用法:
@base: #f04615;
@width: 0.5;
.class {
width: percentage(0.5); // returns `50%`
color: saturate(@base, 5%);
background-color: spin(lighten(@base, 25%), 8);
}
命名空間
有時候,你可能爲了更好組織 CSS 或者單純是爲了更好的封裝,將一些變量或者混合模塊打包起來,你可以像下面這樣在 #bundle
中定義一些屬性集之後可以重複使用:
#bundle {
.button () {
display: block;
border: 1px solid black;
background-color: grey;
&:hover { background-color: white }
}
.tab { ... }
.citation { ... }
}
你只需要在 #header a
中像這樣引入 .button
:
#header a {
color: orange;
#bundle > .button;
}
作用域
LESS 中的作用域跟其他編程語言非常類似,首先會從本地查找變量或者混合模塊,如果沒找到的話會去父級作用域中查找,直到找到爲止。
@var: red;
#page {
@var: white;
#header {
color: @var; // white
}
}
#footer {
color: @var; // red
}
註釋
CSS 的註釋格式在 LESS 中依然有效:
/* Hello, I'm a CSS-style comment */
.class { color: black }
LESS 同樣也支持雙斜線的註釋,但是編譯成 CSS 的時候自動過濾掉:
// Hi, I'm a silent comment, I won't show up in your CSS
.class { color: white }
導入(Import)
在LESS中,你既可以導入CSS文件,也可以導入LESS文件。但只有導入的LESS文件纔會被處理(編譯),導入的CSS文件會保持原樣。如果你希望導入一個CSS文件,保留.css
後綴即可:
@import "lib.css";
編譯過程中,對導入CSS文件只做一處處理:將導入的語句提到最前,緊跟在@charset
之後。
例如輸入的文件有導入語句:
h1 { color: green; }
@import "import/official-branding.css?urlParameter=23";
導入語句將被提到最前:
@import "import/official-branding.css?urlParameter=23";
h1 { color: green; }
被導入的LESS文件會被複制到含導入語句的文件中,然後一起編譯。導入和被導入的文件共享所有的混合、命名空間、變量以及其它結構。
另外,如果導入語句是通過media query指定的,那麼導入的語句編譯之後會被包裹在@Media聲明中。
例如有被導入的文件library.less
:
@imported-color: red;
h1 { color: green; }
主樣式文件導入了上面的library.less
:
@import "library.less" screen and (max-width: 400px); // 通過media query指定的import
@import "library.less"; // 無media query的import
.class {
color: @importedColor; // 使用導入的變量
}
將會編譯出:
// 對應通過media query指定的import
@media screen and (max-width: 400px) {
h1 { color: green; }
}
// 對應無media query的import
h1 { color: green; }
.class {
// 使用導入的變量
color: #ff0000;
}
LESS文件的導入語句並不強制要求在頂部,它可以被入在規則內部、混合中或者其它的結構中。
例如放在規則內部:
pre {
@import "library.less";
color: @importedColor;
}
在library.less
中定義的變量和規則都會被投籃到pre
的規則中:
pre {
color: #ff0000; // 定義在library.less中的變量可用
}
pre h1 { // 定義在library.less中的樣式規則被嵌套到pre中
color: green;
}
在v1.3.0 - v1.3.3中,@import
允許多次導入同一個文件,可以使用@import-once
讓同一文件只導入一次。
在v1.4.0中,移除了@import-once
,@import
的行爲就是同一文件只導入一次了。這意味着,如果代碼是這樣的:
@import “file.less”; @import “file.less”;
那麼第二個文件將被忽略。
任何不以.css
結尾的文件都被認爲是less文件,將被處理。另外,如果文件名沒有後綴,LESS會自動在結尾加上.less
。下面兩種寫法是等價的:
@import "lib.less";
@import "lib";
在v1.4.0中,你可以強制某個文件使用特寫的方式來處理,比如:
@import (css) "lib";
將會輸出:
@import "lib";
而
@import (less) "lib.css";
會將lib.css
引入,並當作LESS文件處理。如果你指定了某個文件是less但是沒有包含後綴名,LESS將不會自動添加後綴。
字符串插值
變量可以用像 @{name}
這樣的結構,以類似 ruby 和 php 的方式嵌入到字符串中:
@base-url: "http://assets.fnord.com";
background-image: url("@{base-url}/images/bg.png");
避免編譯
有時候我們需要輸出一些不正確的 CSS 語法或者使用一些 LESS 不認識的專有語法。
要輸出這樣的值我們可以在字符串前加上一個 ~,例如:
.class {
filter: ~"ms:alwaysHasItsOwnSyntax.For.Stuff()";
}
這叫作“避免編譯”,輸出結果爲:
.class {
filter: ms:alwaysHasItsOwnSyntax.For.Stuff();
}
在避免編譯的值中間也可以像字符串一樣插入變量:
.class {
@what: "Stuff";
filter: ~"ms:alwaysHasItsOwnSyntax.For.@{what}()";
}
選擇器插值
如果需要在選擇器中使用 LESS 變量,只需通過使用和字符串插件一樣的 @{selector}
即可,例如:
@name: blocked;
.@{name} {
color: black;
}
輸出:
.blocked {
color: black;
}
注意:(~"@{name}")
語句可以在 LESS 1.3.1 等之前版本中使用,但 1.4.0 版將不再支持這種用法。
media query作爲變量
如果你希望在media query中使用LESS變量,你可以直接使用普通的變量方式。例如:
@singleQuery: ~"(max-width: 500px)";
@media screen, @singleQuery {
set {
padding: 3 3 3 3;
}
}
被編譯爲:
@media screen, (max-width: 500px) {
set {
padding: 3 3 3 3;
}
}
變量必須包含完整的media query。這樣寫會導致報錯:@media screen and @partial {
。
在1.4.0中,在開啓嚴格運算模式的情況下,你也可以在media query的條件中插入變量。如@media screen, (max-width: @width)
{
。
JavaScript求值
在LESS中還可以使用JavaScript表達式來求值。我們不建議謹慎使用這個特性,因爲它會使得LESS在其它平臺的可編譯性變低,也會使得LESS更難維護。如果可能,試着想想能否用一個函數來完成相同的事情,在github上這樣的庫很多。我們有計劃開放對函數的擴展。但,如果你仍然想用的話,你可以通過反引號的方式使用:
@var: `"hello".toUpperCase() + '!'`;
輸出:
@var: "HELLO!";
注意你也可以同時使用字符串插值和避免編譯:
@str: "hello";
@var: ~`"@{str}".toUpperCase() + '!'`;
輸出:
@var: HELLO!;
它也可以訪問 JavaScript 環境:
@height: `document.body.clientHeight`;
如果你想將一個 JavaScript 字符串解析成16進制的顏色值,你可以使用 color 函數:
@color: color(`window.colors.baseColor`);
@darkcolor: darken(@color, 10%);