這篇文章主要介紹前端構(gòu)建CSS預處理器的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
目前創(chuàng)新互聯(lián)已為上1000家的企業(yè)提供了網(wǎng)站建設、域名、虛擬空間、網(wǎng)站托管維護、企業(yè)網(wǎng)站設計、淶源網(wǎng)站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
Less 是一門 CSS 預處理語言,它擴充了 CSS 語言,增加了諸如變量、混合(mixin)、函數(shù)等功能,讓 CSS 更易維護、方便制作主題、擴充。
Less 可以運行在 Node、瀏覽器和 Rhino 平臺上。網(wǎng)上有很多第三方工具幫助你編譯 Less 源碼。
一、前言
說到前端構(gòu)建怎能缺少CSS預處理器呢!其實CSS的預處理器有很多啦,比較出名的有Scss、Sass、Stylus和Less。(最近還聽說出現(xiàn)了Autoprefixer等CSS后處理器,可參考@一絲的PPT)
眾多CSS預處理器中Less的語法最接近原生CSS,因此相對來說更容易上手,假如有JS、C#等編程經(jīng)驗的話,其實上述的幾種預處理器的學習成本也不會特別高。下面是我們這陣子的學習筆記,以便日后查閱。
最好的入門教程——官網(wǎng)地址:http://lesscss.org/
最佳實踐之一——Bootstrap
由于內(nèi)容較多,特設目錄一坨:
二、搭建學習環(huán)境
三、內(nèi)聯(lián)樣式和外聯(lián)樣式
四、語法
1. 注釋
2. 變量(Variable)
列表類型
3. 嵌套(Nested)
4. 父選擇器引用(ParentSelector)
5. 導入指令(Import)
6. 繼承(Extend)
7. 混合(Mixin)
8. 選擇、循環(huán)作業(yè)控制
五、運算符
六、函數(shù)
七、通過Lessc將Less引入開發(fā)環(huán)境
八、實戰(zhàn)一下
九、與Grunt結(jié)合
十、總結(jié)
二、搭建學習環(huán)境
搭建Less的學習環(huán)境非常簡單,只需在
標簽前通過引入處理器即可實現(xiàn)瀏覽器端中將less預編譯為css樣式。更有效的方式是通過如下代碼監(jiān)測less樣式,自動編譯為css樣式,從而減少我們修改less代碼后需按F5后才看到實際效果的繁瑣步驟。
三、內(nèi)聯(lián)樣式和外聯(lián)樣式
基于我們現(xiàn)在使用的是瀏覽器端進行預編譯,因此Less可用于內(nèi)聯(lián)樣式和外聯(lián)樣式當中。
內(nèi)聯(lián)樣式如下:
外聯(lián)樣式引入如下:
四、語法
1. 注釋
// 單行注釋,不會作為最終輸出 /* 多行注釋,以原生CSS的/*注釋....*/形式作為最終輸出 */
2. 變量(Variable)
Less中的變量有以下規(guī)則:
以@作為變量的起始標識,變量名由字母、數(shù)字、_和-組成
沒有先定義后使用的規(guī)定;
以最后定義的值為最終值;
可用于rule值、rule屬性、rule屬性部件、選擇器、選擇器部件、字符串拼接;
定義時 "@變量名: 變量值;" 的形式;引用時采用 "@變量名" 或 "@{變量名}" 的形式;
存在作用域,局部作用域優(yōu)先級高于全局作用域。
Less源碼:
@color: color; @dialog: .dialog; @suffix: fix; // 空格將被忽略,若要保留空格則需要使用單引號或雙引號 @hi: 'hello '; @dear: there ; .dialog{ // 用于 rule屬性部件,必須使用"@{變量名}" 的形式 background-@{color}: #888; // 用于 rule屬性,必須使用"@{變量名}" 的形式 @{color}: blue; } // 用于 選擇器,必須使用"@{變量名}" 的形式 @{dialog}{ width: 200px; } @{dialog}::after{ content: ': @{hi}@{dear}!'; // 用于 字符串拼接,必須使用"@{變量名}" 的形式 } @h: 1000px; // 用于 選擇器部件,必須使用"@{變量名}" 的形式 .ie-@{suffix}{ @h: 30px; // 存在作用域,局部作用域優(yōu)先級高于全局作用域。 height: @h; // 用于 屬性值,兩種形式均可使用 line-height: 30px; } // 1. 以@作為變量的起始標識,變量名由字母、數(shù)字、_和-組成 // 2. 沒有先定義后使用的規(guī)定; @dialog-border-color: #666; @dialog-border-width: 10px; @dialog-border-width: 1px; // 3. 以最后定義的值為最終值;
最終輸出:
.dialog { background-color: #888; color: blue; } .dialog { width: 200px; } .dialog::after { content: ': hello there!'; } .ie-fix { height: 30px; line-height: 30px; }
列表類型
less變量除了支持#FFF,12px,12,test等單值類型外,還支持列表類型,通過內(nèi)置函數(shù)extract通過索引獲取列表元素,通過內(nèi)置函數(shù)length獲取列表的元素個數(shù)
@colors: #FFF, #0F0, #F0F; .skin{ color: extract(@colors, 0); height: 12px * length(@colors); }
最終輸出:
.skin{ color: #FFF; height: 36px; }
3. 嵌套(Nested)
Less源碼:
.main{ padding: 10px; > div { width: 100px; } .aside { width: 200px; } }
最終輸出:
.main { padding: 10px; } .main > div { width: 100px; } .main .aside { width: 200px; }
4. 父選擇器引用(ParentSelector)
采用&引用完整的父選擇器
可通過追加和預追加的方式加工&,從而生成新的選擇器
通過&::after等方式添加偽元素、偽類樣式規(guī)則集合
同一個選擇器可使用多個&
通過在選擇器后添加 "空格&"的方式,可將當前選擇器排列到最前面
&指向組選擇器時,會生成新的組選擇器
Less源碼:
/* * 采用&引用完整的父選擇器 * 可通過追加和預追加的方式加工&,從而生成新的選擇器 * 通過&::after等方式添加偽元素樣式規(guī)則集合 * 同一個選擇器可使用多個& * 通過在選擇器后添加 "空格&"的方式,可將當前選擇器排列到最前面 */ @bg: #aaa; #ps1 .btn{ background-color: @bg; border-radius: 5px; &:hover{ background-color: lighten(@bg, 30%); cursor: pointer; } &-msg, &-eof{ color: blue; } .no-borderradius &{ background-image: url('img/btn-bg.png'); } } /* * &指向組選擇器時,會生成新的組選擇器 */ #dummy1, .dummy1{ &:hover{ color: red; } & + &{ font-size: 12px; } }
最終輸出:
/* * 采用&引用完整的父選擇器 * 可通過追加和預追加的方式加工&,從而生成新的選擇器 * 通過&::after等方式添加偽元素樣式規(guī)則集合 * 同一個選擇器可使用多個& * 通過在選擇器后添加 "空格&"的方式,可將當前選擇器排列到最前面 */ #ps1 .btn { background-color: #aaaaaa; border-radius: 5px; } #ps1 .btn:hover { background-color: #f6f6f6; cursor: pointer; } #ps1 .btn-msg, #ps1 .btn-eof { color: blue; } .no-borderradius #ps1 .btn { background-image: url('img/btn-bg.png'); } /* * &指向組選擇器時,會生成新的組選擇器 */ #dummy1:hover, .dummy1:hover { color: red; } #dummy1 + #dummy1, #dummy1 + .dummy1, .dummy1 + #dummy1, .dummy1 + .dummy1 { font-size: 12px; }
5. 導入指令(Import)
less樣式文件可通過 @import '文件路徑';
引入外部的less文件。
注意:
不帶擴展名或帶非.less的擴展名均被視為less文件;
@import可出現(xiàn)在任何位置,而不像css的@import那樣只能放在文件第一行。
另外@import還提供了6個可選配置項(分別為reference,inline,less,css,once,multiple),用來改變引入文件的特性。語法為: @import (reference) '文件路徑'; 。下面為各配置項的具體說明:
1. @import (reference) "文件路徑";
將引入的文件作為樣式庫使用,因此文件中樣式不會被直接編譯為css樣式規(guī)則。當前樣式文件通過extend和mixins的方式引用樣式庫的內(nèi)容。
2. @import (inline) "文件路徑";
用于引入與less不兼容的css文件,通過inline配置告知編譯器不對引入的文件進行編譯處理,直接輸出到最終輸出。注意:引入的文件和當前文件會被編譯為一個樣式樣式
3. @import (less) "文件路徑";
默認使用該配置項,表示引入的文件為less文件。
4. @import (css) "文件路徑";
表示當前操作為CSS中的@import操作。當前文件會輸出一個樣式文件,而被引入的文件自身為一個獨立的樣式文件
5. @import (once) "文件路徑";
默認使用該配置項,表示對同一個資源僅引入一次。
6. @import (multiple) "文件路徑";
表示對同一資源可引入多次。
6. 繼承(Extend)
有兩種語法形式,
Less源碼:
.animal{ color: #fff; } /* 語法1::extend( ){} */ .bear:extend(.animal){ width: 100px; height: 100px; } /* 語法2: { &:extend( ); } */ .deer{ &:extend(.animal); width: 50px; height: 50px; }
最終輸出:
.animal, .bear, .deer { color: #fff; } /* 語法1::extend( ){} */ .bear { width: 100px; height: 100px; } /* 語法2: { &:extend( ); } */ .deer { width: 50px; height: 50px; }
注意事項:
6.1. 父選擇器必須嚴格匹配,除了屬性選擇器中屬性值引號不必匹配外,或添加all關(guān)鍵字外。
Less源碼:
*.parent{ height: 100px; .hair{ color: #f27; } [name=eyes]{ color: #768; } } // 匹配失敗 .son:extend(.parent){} .son:extend(.hair){} // 匹配成功 .son:extend(*.parent [name='eyes']){} .son:extend(*.parent [name="eyes"]){} // all關(guān)鍵字會匹配所有包含parentSelector內(nèi)容的選擇器,并以selector替換parentSelector來生成新的選擇器 // 下面的內(nèi)容會生成 *.son,*.son .hair,*.son [name=eyes]三個新的選擇器 .son:extend(.parent all){}
最終輸出:
*.parent, *.son { height: 100px; } *.parent .hair, *.son .hair { color: #f27; } *.parent [name=eyes], .son, .son, *.son [name=eyes] { color: #768; }
6.2. 父選擇器不支持變量形式
Less源碼:
@p1: .parent1; @p2: .parent2; .parent1{ height: 100px; } @{p2}{ height: 200px; } // 匹配失敗 // 形式1,不支持以變量作入?yún)? .son1:extend(@{p1}){} // 形式2,不支持以變量作為選擇器的規(guī)則集合 .son1:extend(.parent2){} // 匹配成功 .son2:extend(.parent1){} @s3: son3; .@{s3}:extend(.parent1){}
最終輸出:
.parent1, .son2, .son3 { height: 100px; } .parent2 { height: 200px; }
6.3. media query影響繼承的作用域
6.3.1. media query內(nèi)的extend操作,僅能繼承當前塊的其他選擇器樣式。
注意:不能extend當前media query塊內(nèi)部的子media query塊中的選擇器樣式;但可以extend父media query塊的選擇器樣式。
Less源碼:
.parent1{ height: 200px; } @media screen{ .parent1{ height: 100px; } // 無法繼承子media query塊的選擇器樣式 .son1:extend(.parent2){} @media (min-width: 1023px){ // 繼承父media query塊的選擇器樣式 .son2:extend(.parent1){} .parent2{ width: 200px; } } }
最終輸出:
.parent1 { height: 200px; } @media screen { .parent1 { height: 100px; } } @media screen and (min-width: 1023px) { .parent2 { width: 200px; } }
6.3.2. 非media query內(nèi)的extend操作,將會繼承所有media query中匹配的選擇器樣式。
Less源碼:
@media screen{ .parent{ height: 100px; } @media (min-width: 1023px){ .parent{ width: 200px; } } } .son:extend(.parent){}
最終輸出:
@media screen { .parent, .son { height: 100px; } } @media screen and (min-width: 1023px) { .parent, .son { width: 200px; } }
6.4. 增強的mixin定義mixin時僅能使用類選擇器和ID選擇器,而extend操作可對應所有的選擇器,因此當沒有動態(tài)入?yún)⒍中枰愡x擇器和ID選擇器以外的選擇器時,可使用extend來實現(xiàn)mixin的功能。
7. 混合(Mixin)
Mixin相當于macro,會將樣式規(guī)則內(nèi)聯(lián)到調(diào)用的位置中。而Less中的mixin有以下的注意點:
7.1. 類選擇器、ID選擇器自動被定義為mixin,而且具有命名空間;
Less源碼:
.animal{ .human{ #fsjohnhuang{ .hair{ color: #000; } } } } .front-end-monkey{ // 或者.animal.human#fsjohnhuang.hair(); // 或者.animal>.human>#fsjohnhuang>.hair; // 或者.animal>.human>#fsjohnhuang>.hair(); // 即可調(diào)用mixin .animal.human#fsjohnhuang.hair; }
最終輸出:
.animal .human #fsjohnhuang .hair { color: #000; } .front-end-monkey { color: #000; }
7.2. 顯示定義不帶參數(shù)和帶參數(shù)的樣式庫(mixin庫),不會輸出到最終輸出中,僅供調(diào)用;
Less源碼:
// 定義不帶參數(shù)的mixin .animal(){ color: #000; } // 定義帶參數(shù)的mixin // 注意:由于,和;均可用于作為參數(shù)分隔符,但由于如background、border等樣式屬性支持屬性值組,而,則作為屬性值組元素分隔符,因此推薦使用;作為參數(shù)分隔符 .dog(@type; @age){ height: @type * @age * 12px; } // 定義帶參數(shù)默認值的mixin .cat(@type; @age:1){ height: @type * @age * 5px; } // 調(diào)用才會出現(xiàn)在最終輸出 .chihuahua{ .dog(1;2); }
最終輸出:
.chihuahua { height: 24px; }
7.3. mixin內(nèi)置兩個特殊的對象 @arguments 和 @reset 。@arguments代表mixin的所有入?yún)?而@reset代表mixin的...入?yún)?shù)組。
Less源碼:
.dog(@type;@age;@rest...){ height: @type * @age * 12px; border: @rest; } .cat(@solid;@w;@color){ border: @arguments; } .chihuahua{ .dog(1;2;solid;1px;red); } .mimi{ .cat(solid;2px;blue); }
最終輸出:
.chihuahua { height: 24px; border: solid 1px red; } .mimi { border: solid 2px blue; }
7.4. mixin的重載可定義多個同名mixin,調(diào)用時只要參數(shù)數(shù)量匹配則會執(zhí)行相應的mixin。
Less源碼:
.dog(@name){ &::after{ content: @name; } } .dog(@name;@age){ height: @age * 4px; } .dog(@name;@age;@width:20px){ height: @age * 12px; width: @width; } // 僅匹配到 .dog(@name){ .one-dog{ .dog('chihuahua'); } // 匹配到.dog(@name;@age) 和 .dog(@name;@age;@width:20px) .two-three-dog{ .dog('two-three-dog', 2); } // 參數(shù)的模式匹配 // 當?shù)谝粎?shù)值為mimi時調(diào)用該mixin .cat(mimi, @age){ height: @age * 22px; } // 當?shù)谝粎?shù)值為mini時調(diào)用該mixin .cat(mini, @age){ height: @age * 12px; } // 不管第一參數(shù)值為啥均調(diào)用該mixin .cat(@any, @age){ color: #f3c; } .mycat{ .cat(mini, 1); }
最終輸出:
.one-dog::after { content: 'chihuahua'; } .two-three-dog { height: 8px; height: 24px; width: 20px; } .mycat { height: 12px; color: #f3c; }
8. 選擇、循環(huán)作業(yè)控制
Less中通過混合(Mixin)后的when關(guān)鍵字來提供選擇的作業(yè)控制,通過遞歸來實現(xiàn)循環(huán)的作業(yè)控制。
Less源碼:
// 條件匹配 // true值匹配,僅實參為true時才匹配成功 .truth(@a) when (@a){ &::after{ content: @a; } } // 匹配成功 .truth2{ .truth(true); } // 匹配失敗 .truth3{ .truth(#fff); } /* 類型判斷函數(shù) * iscolor * isnumber * isstring * iskeyword * isurl */ .bear(@color) when (iscolor(@color)){ color: @color; } /* 單位判斷函數(shù) * ispixel * ispercentage * isem * isunit */ .bear(@height) when (ispixel(@height)){ height: @height; } // =,>,>=,<=,< 關(guān)系運算符 .rich(@h) when (@h > 1000){ height: @h; } // and、not、or(使用,號表示) 邏輯運算符 .huge(@h, @w) when (@h > 180) and (@w > 180){ height: @h; width: @w; } // 使用& when()實現(xiàn)if語句 @debug: true; & when (@debug){ div{ border: solid 1px red; } } // 通過遞歸實現(xiàn)循環(huán) .generate-columns(4); .generate-columns(@n, @i: 1) when (@i =< @n) { .column-@{i} { width: (@i * 100% / @n); } .generate-columns(@n, (@i + 1)); }
最終輸出:
.truth2::after { content: true; } /* 類型判斷函數(shù) * iscolor * isnumber * isstring * iskeyword * isurl */ /* 單位判斷函數(shù) * ispixel * ispercentage * isem * isunit */ div { border: solid 1px red; } .column-1 { width: 25%; } .column-2 { width: 50%; } .column-3 { width: 75%; } .column-4 { width: 100%; }
五、運算符
Less還支持+、-、*、/運算符。但對單位不一致的運算數(shù)進行運算要注意以下兩點:
1. 運算數(shù)與運算符間必須用空格分隔;
2. 以第一個運算數(shù)的單位作為運算結(jié)果的單位;
Less源碼:
// 運算數(shù)與運算符間沒有空格 @fail: 1px +2em; .fail{ height: @fail; } @success1: 1px + 2em; .success1{ height: @success1; } @success2: 2px + 1em; .success2{ height: @success2; }
最終輸出:
.fail{ height: 1px 2em; } .success1{ height: 3px; } .success2{ height: 3em; }
六、函數(shù)
Less為我們提供了一個功能強大的內(nèi)置函數(shù)庫,其中絕大部分為顏色處理函數(shù)。下面著重介紹Misc Function中的default函數(shù)、String Function中的escape函數(shù)和顏色處理函數(shù)。
1. default函數(shù)
示例:
// for teenager .person(@age) when (@age <= 19) and (@age >=13){ height: @age * 10px; } // for child .person(@age) when (@age <13){ height: @age * 6px; } // for adult .person(@age) when (default()){ height: 180px; } .son{ .person(10); } .daughter{ person(17); } .father{ .person(27); }
最終輸出:
.son{ height: 60px; } .daughter{ height: 170px; } .father{ height: 180px; }
雖然上述示例邏輯上不合理。但可以看出default函數(shù)用于條件控制當中,充當else或switch語句中default的角色。
通過官網(wǎng)提供的綜合示例我們可以更好理解它的用法:
// Less源碼 .x { .m(red) {case-1: darkred} .m(blue) {case-2: darkblue} .m(@x) when (iscolor(@x)) and (default()) {default-color: @x} .m('foo') {case-1: I am 'foo'} .m('bar') {case-2: I am 'bar'} .m(@x) when (isstring(@x)) and (default()) {default-string: and I am the default} &-blue {.m(blue)} &-green {.m(green)} &-foo {.m('foo')} &-baz {.m('baz')} } // 最終輸出 .x-blue { case-2: #00008b; } .x-green { default-color: #008000; } .x-foo { case-1: I am 'foo'; } .x-baz { default-string: and I am the default; }
注意:
1. default函數(shù)必須在條件控制語句當中使用;
2. default函數(shù)可實現(xiàn)比else更復雜的功能,如下:
// Less源碼 .mixin(@value) when (ispixel(@value)) {width: @value} .mixin(@value) when not(default()) {padding: (@value / 5)} div-1 { .mixin(100px); } div-2 { /* ... */ .mixin(100%); } // 最終輸出: div-1 { width: 100px; padding: 20px; } div-2 { /* ... */ }
2. escape函數(shù)
顧名思義就是對字符串中的特定字符進行編碼,該函數(shù)將對\
3. 顏色處理函數(shù)
顏色處理函數(shù)又分為四大類:顏色定義函數(shù)(Color Definition)、顏色通道值獲取函數(shù)(Color Channel)、顏色通道值修改函數(shù)(Color Operation Function)、混色函數(shù)(Color Blending)。
這里僅僅介紹常用的lighten和darken函數(shù)。
lighten(color, amount) ,color為顏色,amount為增加的亮度值,取值范圍為0-100%。
darken(color, amount) ,color為顏色,amount為減少的亮度值,取值范圍為0-100%。
七、通過Lessc將Less引入開發(fā)環(huán)境
到這里我想大家已經(jīng)對Less有一定程度的了解,并希望在將其加入你的開發(fā)工具包中。但通過less.js將Less解析器引入到瀏覽器肯定是不適合開發(fā)的,而cli工具lessc更適合開發(fā)環(huán)境中使用。在使用之前我們先要通過npm來安裝less。
npm install -g less
然后我們就可以通過 lessc [option option=parameter ...]
lessc的option選項較多,我將主要的選項分為lessc命令信息相關(guān)、sourcemap相關(guān)、@import指令相關(guān)和插件相關(guān)四類。
1. lessc命令信息相關(guān)
lessc -h ,獲取lessc命令的幫助信息;
lessc -v ,獲取lessc命令的版本號。
2. sourcemap相關(guān)
由于在瀏覽器直接查看和操作的是CSS樣式規(guī)則,而我們開發(fā)時使用的Less代碼,這會導致難以找到CSS樣式規(guī)則所對應的Less代碼從而增大調(diào)試難度。而sourcemap就是為了解決這一痛點而提出的技術(shù)解決方案,其原理就是通過一個map文件來保存兩個文件中代碼的對應關(guān)系,然后支持sourcemap的瀏覽器的devTools中就會根據(jù)這些對應關(guān)系來定位相應的Less代碼。(Chrome和FF均支持sourcemap,IE11及以下均不支持)
若對sourcemap不太了解的可以參考《前端構(gòu)建:Source Maps詳解》
--source-map ,生成與生成的css同名的sourcemap文件(例如生成的css文件為main.css,那么sourcemap文件就是main.css.map),且與css文件位于同一目錄下;
--source-map=
--source-map-rootpath=
lessc --source-map --source-map-rootpath=../../src/less/main.less src/less/main.less bin/style/main.css
--source-map-map-inline ,以data URI Scheme的形式將sourcemap文件內(nèi)容內(nèi)嵌到css文件中。
--source-map-url=
3. @import指令相關(guān)
--include-path=
--relative-urls 或 -ru ,用于保持樣式庫中的圖片等資源的相對路徑。示例:
# main.less @import "files/backgrounds.less"; # files/backgrounds.less .icon-1 { background-image: url('images/lamp-post.png'); }
不使用該選項時:
.icon-1 { background-image: url('images/lamp-post.png'); }
使用該選項時:
.icon-1 { background-image: url('files/images/lamp-post.png'); }
4. 插件相關(guān)
lessc以插件的形式來增強其功能,下面僅介紹clean-css插件,其他插件請參考/upload/otherpic73/76434
|-- src 源碼
| |-- less
| | |-- main.less
| |-- index.html
|-- bin 編譯后的文件
| |-- style
| |-- main.css
| |-- main.css.map
| |-- index.html
|-- dist 發(fā)布文件
|-- lib
| |-- less
| |-- img
| |-- nav.png
|-- app
|-- style
| |--main.css
|-- index.html
index.html文件內(nèi)容: