十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
这篇文章主要介绍前端构建CSS预处理器的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
目前创新互联已为上1000家的企业提供了网站建设、域名、虚拟空间、网站托管维护、企业网站设计、涞源网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量、混合(mixin)、函数等功能,让 CSS 更易维护、方便制作主题、扩充。
Less 可以运行在 Node、浏览器和 Rhino 平台上。网上有很多第三方工具帮助你编译 Less 源码。
一、前言
说到前端构建怎能缺少CSS预处理器呢!其实CSS的预处理器有很多啦,比较出名的有Scss、Sass、Stylus和Less。(最近还听说出现了Autoprefixer等CSS后处理器,可参考@一丝的PPT)
众多CSS预处理器中Less的语法最接近原生CSS,因此相对来说更容易上手,假如有JS、C#等编程经验的话,其实上述的几种预处理器的学习成本也不会特别高。下面是我们这阵子的学习笔记,以便日后查阅。
最好的入门教程——官网地址:http://lesscss.org/
最佳实践之一——Bootstrap
由于内容较多,特设目录一坨:
二、搭建学习环境
三、内联样式和外联样式
四、语法
1. 注释
2. 变量(Variable)
列表类型
3. 嵌套(Nested)
4. 父选择器引用(ParentSelector)
5. 导入指令(Import)
6. 继承(Extend)
7. 混合(Mixin)
8. 选择、循环作业控制
五、运算符
六、函数
七、通过Lessc将Less引入开发环境
八、实战一下
九、与Grunt结合
十、总结
二、搭建学习环境
搭建Less的学习环境非常简单,只需在
标签前通过引入处理器即可实现浏览器端中将less预编译为css样式。更有效的方式是通过如下代码监测less样式,自动编译为css样式,从而减少我们修改less代码后需按F5后才看到实际效果的繁琐步骤。
三、内联样式和外联样式
基于我们现在使用的是浏览器端进行预编译,因此Less可用于内联样式和外联样式当中。
内联样式如下:
外联样式引入如下:
四、语法
1. 注释
// 单行注释,不会作为最终输出 /* 多行注释,以原生CSS的/*注释....*/形式作为最终输出 */
2. 变量(Variable)
Less中的变量有以下规则:
以@作为变量的起始标识,变量名由字母、数字、_和-组成
没有先定义后使用的规定;
以最后定义的值为最终值;
可用于rule值、rule属性、rule属性部件、选择器、选择器部件、字符串拼接;
定义时 "@变量名: 变量值;" 的形式;引用时采用 "@变量名" 或 "@{变量名}" 的形式;
存在作用域,局部作用域优先级高于全局作用域。
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; // 存在作用域,局部作用域优先级高于全局作用域。 height: @h; // 用于 属性值,两种形式均可使用 line-height: 30px; } // 1. 以@作为变量的起始标识,变量名由字母、数字、_和-组成 // 2. 没有先定义后使用的规定; @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等单值类型外,还支持列表类型,通过内置函数extract通过索引获取列表元素,通过内置函数length获取列表的元素个数
@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等方式添加伪元素、伪类样式规则集合
同一个选择器可使用多个&
通过在选择器后添加 "空格&"的方式,可将当前选择器排列到最前面
&指向组选择器时,会生成新的组选择器
Less源码:
/* * 采用&引用完整的父选择器 * 可通过追加和预追加的方式加工&,从而生成新的选择器 * 通过&::after等方式添加伪元素样式规则集合 * 同一个选择器可使用多个& * 通过在选择器后添加 "空格&"的方式,可将当前选择器排列到最前面 */ @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等方式添加伪元素样式规则集合 * 同一个选择器可使用多个& * 通过在选择器后添加 "空格&"的方式,可将当前选择器排列到最前面 */ #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可出现在任何位置,而不像css的@import那样只能放在文件第一行。
另外@import还提供了6个可选配置项(分别为reference,inline,less,css,once,multiple),用来改变引入文件的特性。语法为: @import (reference) '文件路径'; 。下面为各配置项的具体说明:
1. @import (reference) "文件路径";
将引入的文件作为样式库使用,因此文件中样式不会被直接编译为css样式规则。当前样式文件通过extend和mixins的方式引用样式库的内容。
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关键字外。
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关键字会匹配所有包含parentSelector内容的选择器,并以selector替换parentSelector来生成新的选择器 // 下面的内容会生成 *.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,不支持以变量作入参 .son1:extend(@{p1}){} // 形式2,不支持以变量作为选择器的规则集合 .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内的extend操作,仅能继承当前块的其他选择器样式。
注意:不能extend当前media query块内部的子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内的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操作可对应所有的选择器,因此当没有动态入参而又需要类选择器和ID选择器以外的选择器时,可使用extend来实现mixin的功能。
7. 混合(Mixin)
Mixin相当于macro,会将样式规则内联到调用的位置中。而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(); // 即可调用mixin .animal.human#fsjohnhuang.hair; }
最终输出:
.animal .human #fsjohnhuang .hair { color: #000; } .front-end-monkey { color: #000; }
7.2. 显示定义不带参数和带参数的样式库(mixin库),不会输出到最终输出中,仅供调用;
Less源码:
// 定义不带参数的mixin .animal(){ color: #000; } // 定义带参数的mixin // 注意:由于,和;均可用于作为参数分隔符,但由于如background、border等样式属性支持属性值组,而,则作为属性值组元素分隔符,因此推荐使用;作为参数分隔符 .dog(@type; @age){ height: @type * @age * 12px; } // 定义带参数默认值的mixin .cat(@type; @age:1){ height: @type * @age * 5px; } // 调用才会出现在最终输出 .chihuahua{ .dog(1;2); }
最终输出:
.chihuahua { height: 24px; }
7.3. mixin内置两个特殊的对象 @arguments 和 @reset 。@arguments代表mixin的所有入参,而@reset代表mixin的...入参数组。
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,调用时只要参数数量匹配则会执行相应的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); } // 参数的模式匹配 // 当第一参数值为mimi时调用该mixin .cat(mimi, @age){ height: @age * 22px; } // 当第一参数值为mini时调用该mixin .cat(mini, @age){ height: @age * 12px; } // 不管第一参数值为啥均调用该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. 选择、循环作业控制
Less中通过混合(Mixin)后的when关键字来提供选择的作业控制,通过递归来实现循环的作业控制。
Less源码:
// 条件匹配 // true值匹配,仅实参为true时才匹配成功 .truth(@a) when (@a){ &::after{ content: @a; } } // 匹配成功 .truth2{ .truth(true); } // 匹配失败 .truth3{ .truth(#fff); } /* 类型判断函数 * iscolor * isnumber * isstring * iskeyword * isurl */ .bear(@color) when (iscolor(@color)){ color: @color; } /* 单位判断函数 * ispixel * ispercentage * isem * isunit */ .bear(@height) when (ispixel(@height)){ height: @height; } // =,>,>=,<=,< 关系运算符 .rich(@h) when (@h > 1000){ height: @h; } // and、not、or(使用,号表示) 逻辑运算符 .huge(@h, @w) when (@h > 180) and (@w > 180){ height: @h; width: @w; } // 使用& when()实现if语句 @debug: true; & when (@debug){ div{ border: solid 1px red; } } // 通过递归实现循环 .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; } /* 类型判断函数 * iscolor * isnumber * isstring * iskeyword * isurl */ /* 单位判断函数 * 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还支持+、-、*、/运算符。但对单位不一致的运算数进行运算要注意以下两点:
1. 运算数与运算符间必须用空格分隔;
2. 以第一个运算数的单位作为运算结果的单位;
Less源码:
// 运算数与运算符间没有空格 @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; }
六、函数
Less为我们提供了一个功能强大的内置函数库,其中绝大部分为颜色处理函数。下面着重介绍Misc Function中的default函数、String Function中的escape函数和颜色处理函数。
1. default函数
示例:
// 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函数用于条件控制当中,充当else或switch语句中default的角色。
通过官网提供的综合示例我们可以更好理解它的用法:
// 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函数必须在条件控制语句当中使用;
2. default函数可实现比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函数
顾名思义就是对字符串中的特定字符进行编码,该函数将对\
3. 颜色处理函数
颜色处理函数又分为四大类:颜色定义函数(Color Definition)、颜色通道值获取函数(Color Channel)、颜色通道值修改函数(Color Operation Function)、混色函数(Color Blending)。
这里仅仅介绍常用的lighten和darken函数。
lighten(color, amount) ,color为颜色,amount为增加的亮度值,取值范围为0-100%。
darken(color, amount) ,color为颜色,amount为减少的亮度值,取值范围为0-100%。
七、通过Lessc将Less引入开发环境
到这里我想大家已经对Less有一定程度的了解,并希望在将其加入你的开发工具包中。但通过less.js将Less解析器引入到浏览器肯定是不适合开发的,而cli工具lessc更适合开发环境中使用。在使用之前我们先要通过npm来安装less。
npm install -g less
然后我们就可以通过 lessc [option option=parameter ...]
lessc的option选项较多,我将主要的选项分为lessc命令信息相关、sourcemap相关、@import指令相关和插件相关四类。
1. lessc命令信息相关
lessc -h ,获取lessc命令的帮助信息;
lessc -v ,获取lessc命令的版本号。
2. sourcemap相关
由于在浏览器直接查看和操作的是CSS样式规则,而我们开发时使用的Less代码,这会导致难以找到CSS样式规则所对应的Less代码从而增大调试难度。而sourcemap就是为了解决这一痛点而提出的技术解决方案,其原理就是通过一个map文件来保存两个文件中代码的对应关系,然后支持sourcemap的浏览器的devTools中就会根据这些对应关系来定位相应的Less代码。(Chrome和FF均支持sourcemap,IE11及以下均不支持)
若对sourcemap不太了解的可以参考《前端构建: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文件内容内嵌到css文件中。
--source-map-url=
3. @import指令相关
--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. 插件相关
lessc以插件的形式来增强其功能,下面仅介绍clean-css插件,其他插件请参考/upload/otherpic73/76434
|-- src 源码
| |-- less
| | |-- main.less
| |-- index.html
|-- bin 编译后的文件
| |-- style
| |-- main.css
| |-- main.css.map
| |-- index.html
|-- dist 发布文件
|-- lib
| |-- less
| |-- img
| |-- nav.png
|-- app
|-- style
| |--main.css
|-- index.html
index.html文件内容: