前端构建:Less入了个门
一、前言
说到前端构建怎能缺少CSS预处理器呢!其实CSS的预处理器有很多啦,比较出名的有Scss、Sass、Stylus和Less。(最近还听说出现了Autoprefixer等CSS后处理器,可参考@一丝的PPT)
众多CSS预处理器中Less的语法最接近原生CSS,因此相对来说更容易上手,假如有JS、C#等编程经验的话,其实上述的几种预处理器的学习成本也不会特别高。下面是我们这阵子的学习笔记,以便日后查阅。
最好的入门教程——官网地址:http://lesscss.org/
最佳实践之一——Bootstrap
由于内容较多,特设目录一坨:
6.1. 父选择器必须严格匹配,除了属性选择器中属性值引号不必匹配外,或添加all关键字外。
6.3.1. media query内的extend操作,仅能继承当前块的其他选择器样式。
6.3.2. 非media query内的extend操作,将会继承所有media query中匹配的选择器样式。
7.1. 类选择器、ID选择器自动被定义为mixin,而且具有命名空间;
7.2. 显示定义不带参数和带参数的样式库(mixin库),不会输出到最终输出中,仅供调用;
7.3. mixin的中内置两个特殊的对象@arguments和@reset。@argumentsk代表mixin的所有入参,而@reset代表mixin的...入参数组。
7.4. mixin的重载可定义多个同名mixin,调用时只要参数数量匹配则会执行相应的mixin。
二、搭建学习环境
搭建Less的学习环境非常简单,只需在</body>标签前通过<script type="text/javascript" src="less.js"></script>引入处理器即可实现浏览器端中将less预编译为css样式。更有效的方式是通过如下代码监测less样式,自动编译为css样式,从而减少我们修改less代码后需按F5后才看到实际效果的繁琐步骤。
- <script>less = { env: 'development'};</script>
- <script src="less.js"></script>
- <script>less.watch();</script>
三、内联样式和外联样式
基于我们现在使用的是浏览器端进行预编译,因此Less可用于内联样式和外联样式当中。
内联样式如下:
- <style type="text/less">
- // less 代码
- </style>
外联样式引入如下:
- <link rel="stylesheet/less" type="text/css" href="文件.less"/>
四、语法
1. 注释
- // 单行注释,不会作为最终输出
- /*
- 多行注释,以原生CSS的/*注释....*/形式作为最终输出
- */
2. 变量(Variable)
Less中的变量有以下规则:
- 以@作为变量的起始标识,变量名由字母、数字、_和-组成
- 没有先定义后使用的规定;
- 以最后定义的值为最终值;
- 可用于rule值、rule属性、rule属性部件、选择器、选择器部件、字符串拼接;
- 定义时 "@变量名: 变量值;" 的形式;引用时采用 "@变量名" 或 "@{变量名}" 的形式;
- 存在作用域,局部作用域优先级高于全局作用域。
Less源码:
- @color: color;
- @dialog: .dialog;
- @suffix: fix;
- // 空格将被忽略,若要保留空格则需要使用单引号或双引号
- @hi: 'hello ';
- @dear: there ;
- .dialog{
- // 用于 rule属性部件,必须使用"@{变量名}" 的形式
- background-@{color}: #;
- // 用于 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: #;
- @dialog-border-width: 10px;
- @dialog-border-width: 1px; // 3. 以最后定义的值为最终值;
最终输出:
- .dialog {
- background-color: #;
- 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, );
- 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, %);
- 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)
有两种语法形式, <selector>:extend(<parentSelector>){} 和 <selector>{ &:extend(<parentSelector>); }
Less源码:
- .animal{
- color: #fff;
- }
- /* 语法1:<selector>:extend(<parentSelector>){} */
- .bear:extend(.animal){
- width: 100px;
- height: 100px;
- }
- /* 语法2:<selector>{ &:extend(<parentSelector>); } */
- .deer{
- &:extend(.animal);
- width: 50px;
- height: 50px;
- }
最终输出:
- .animal,
- .bear,
- .deer {
- color: #fff;
- }
- /* 语法1:<selector>:extend(<parentSelector>){} */
- .bear {
- width: 100px;
- height: 100px;
- }
- /* 语法2:<selector>{ &:extend(<parentSelector>); } */
- .deer {
- width: 50px;
- height: 50px;
- }
注意事项:
- 6.1. 父选择器必须严格匹配,除了属性选择器中属性值引号不必匹配外,或添加all关键字外。
- Less源码:
- *.parent{
- height: 100px;
- .hair{
- color: #f27;
- }
- [name=eyes]{
- color: #;
- }
- }
- // 匹配失败
- .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: #;
- }
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: #;
- }
- }
- }
- }
- .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: #;
- }
- .front-end-monkey {
- color: #;
- }
7.2. 显示定义不带参数和带参数的样式库(mixin库),不会输出到最终输出中,仅供调用;
Less源码:
- // 定义不带参数的mixin
- .animal(){
- color: #;
- }
- // 定义带参数的mixin
- // 注意:由于,和;均可用于作为参数分隔符,但由于如background、border等样式属性支持属性值组,而,则作为属性值组元素分隔符,因此推荐使用;作为参数分隔符
- .dog(@type; @age){
- height: @type * @age * 12px;
- }
- // 定义带参数默认值的mixin
- .cat(@type; @age:){
- height: @type * @age * 5px;
- }
- // 调用才会出现在最终输出
- .chihuahua{
- .dog(;);
- }
最终输出:
- .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(;;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', );
- }
- // 参数的模式匹配
- // 当第一参数值为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, );
- }
最终输出:
- .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;
- }
- }
- // 匹配成功
- .truth1{
- .truth(true);
- }
- // 匹配失败
- .truth2{
- .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 > ){
- height: @h;
- }
- // and、not、or(使用,号表示) 逻辑运算符
- .huge(@h, @w) when (@h > ) and (@w > ){
- height: @h;
- width: @w;
- }
- // 使用& when()实现if语句
- @debug: true;
- & when (@debug){
- div{
- border: solid 1px red;
- }
- }
- // 通过递归实现循环
- .generate-columns();
- .generate-columns(@n, @i: ) when (@i =< @n) {
- .column-@{i} {
- width: (@i * % / @n);
- }
- .generate-columns(@n, (@i + ));
- }
最终输出:
- .truth1::after {
- content: true;
- }
- /* 类型判断函数
- * iscolor
- * isnumber
- * isstring
- * iskeyword
- * isurl
- */
- /* 单位判断函数
- * ispixel
- * ispercentage
- * isem
- * isunit
- */
- div {
- border: solid 1px red;
- }
- .column- {
- width: %;
- }
- .column- {
- width: %;
- }
- .column- {
- width: %;
- }
- .column- {
- width: %;
- }
五、运算符
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 <= ) and (@age >=){
- height: @age * 10px;
- }
- // for child
- .person(@age) when (@age <){
- height: @age * 6px;
- }
- // for adult
- .person(@age) when (default()){
- height: 180px;
- }
- .son{
- .person();
- }
- .daughter{
- person();
- }
- .father{
- .person();
- }
最终输出:
- .son{
- height: 60px;
- }
- .daughter{
- height: 170px;
- }
- .father{
- height: 180px;
- }
虽然上述示例逻辑上不合理。但可以看出default函数用于条件控制当中,充当else或switch语句中default的角色。
通过官网提供的综合示例我们可以更好理解它的用法:
- // Less源码
- .x {
- .m(red) {case-: darkred}
- .m(blue) {case-: darkblue}
- .m(@x) when (iscolor(@x)) and (default()) {default-color: @x}
- .m('foo') {case-: I am 'foo'}
- .m('bar') {case-: 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-: #00008b;
- }
- .x-green {
- default-color: #;
- }
- .x-foo {
- case-: 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 / )}
- div- {
- .mixin(100px);
- }
- div- {
- /* ... */
- .mixin(%);
- }
- // 最终输出:
- div- {
- width: 100px;
- padding: 20px;
- }
- div- {
- /* ... */
- }
2. escape函数
顾名思义就是对字符串中的特定字符进行编码,该函数将对\<space\>
, #
, ^
, (
, )
, {
, }
, |
, :
, >
, <
, ;
, ]
, [ 和
=字符进行编码。
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 ...] <source> [destination] 的命令格式来调用lessc了!
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=<sourcemap文件路径> ,自定义sourcemap文件的路径;
--source-map-rootpath=<sourcemap文件中sources属性值的路径前缀> ,假如main.less文件位于src/less下,而生成的css和sourcemap文件位于bin/style下,那么就需要修改sourcemap文件中用于指向less文件路径的sources属性值,浏览器才能通过sourcemap文件查找到less文件。上述例子的命令为:
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=<css文件中指向sourcemap文件的url> ,默认情况下css文件的最后一行会插入如 /*# sourceMappingURL=main.css.map */ 的内容来指向sourcemap文件,而该选项则可修改sourceMappingURL的值。
3. @import指令相关
--include-path=<path>[;<path>]* ,通过@import指令引入外部less或css等文件时存在引入的文件路径到底是以哪个目录作为参考的问题,我们可以通过该选项来指定参考目录,当存在多个参考目录时,使用;号分隔。
--relative-urls 或 -ru ,用于保持样式库中的图片等资源的相对路径。示例:
- # main.less
- @import "files/backgrounds.less";
- # files/backgrounds.less
- .icon- {
- background-image: url('images/lamp-post.png');
- }
不使用该选项时:
- .icon- {
- background-image: url('images/lamp-post.png');
- }
使用该选项时:
- .icon- {
- background-image: url('files/images/lamp-post.png');
- }
4. 插件相关
lessc以插件的形式来增强其功能,下面仅介绍clean-css插件,其他插件请参考http://lesscss.org/usage/#plugins-list-of-less-plugins
clean-css插件用于压缩css文件(less-plugin-clean-css@github)
首先通过npm安装插件 npm install -g less-plugin-clean-css ,然后通过--clean-css选项来启动CSS压缩功能。
如: lessc file.less --clean-css="--s1 --advanced --compatibility=ie8"
八、实战一下
先假定我们开发环境的目录结构如下(灰色表示文件由构建工具生成):
sample
|-- build.bat 构建工具
|-- lib 第三方依赖库
| |-- less
| |-- base.less
| |-- img
| |-- nav.png
|-- 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文件内容:
- <html>
- <head>
- <title></title>
- <link rel="stylesheet" type="text/css" href="style/main.css"/>
- </head>
- <body>
- <div class="nav">
- </div>
- </body>
- </html>
样式库base.less文件内容:
- .base-nav{
- height: 50px;
- background-image: url(img/nav.png);
- }
- .base-debug{
- border: solid 5px red;
- }
main.less文件内容:
- @import (reference) "base.less";
- @env:release; //编译模式:release或debug
- /* 导航栏 */
- .nav:extend(.base-nav){
- // 编译模式为debug时采用该样式
- & when (@env=debug){
- .base-debug();
- }
- }
我们一般将工程代码级别的产出分为源码、可执行代码 和可发布代码 三种,而可执行代码和可发布代码的构建需求是不同的,因此构建方式也有所区别,也就是lessc使用的选项也会不同。下面将针对不同的产出物来介绍lessc的使用。
1. 可执行代码
我将可执行代码部分再细分为release和debug两种编译模式,可以看到通过变量@env来实现不同模式下采用不同的样式规则。默认采用release模式编译源码。
- lessc --include-path=lib/less --relative-urls --source-map --source-map-rootpath=../../src/less/main.less src/less/main.less bin/style/main.css
在执行lessc命令时通过选项--modify-var="env=debug"即可以debug模式编译源码。
- lessc --include-path=lib/less --relative-urls --source-map --source-map-rootpath=../../src/less/ --modify-var="env=debug" src/less/main.less bin/style/main.css
可以看到上述编译过程中均会生成sourcemap文件以便调试使用。
2. 可发布代码
对于发布的内容我们会对其进行压缩处理
- lessc --include-path=lib/less --clean-css="advanced" --relative-urls src/less/main.less dist/app/style/main.css
由于sourcemap文件仅在开发阶段有用,因此生成发布代码时就不要生成了。
完整的构建文件build.bat如下:
- @echo off
- cls
- goto :%
- :bin
- echo Building......
- ::remove subitems of bin
- rd /S /Q bin
- ::copy html files
- xcopy /y src\*.html bin\
- ::compile less to css
- cmd /C lessc --include-path=lib/less --relative-urls --source-map --source-map-rootpath=../../src/less/main.less src/less/main.less bin/style/main.css
- echo Building is over!
- goto :over
- :debug
- echo Building......
- ::remove subitems of bin
- rd /S /Q bin
- ::copy html files
- xcopy /y src\*.html bin\
- ::compile less to css
- cmd /C lessc --include-path=lib/less --relative-urls --source-map --source-map-rootpath=../../src/less/ --modify-var="env=debug" src/less/main.less bin/style/main.css
- echo Building is over!
- goto :over
- :dist
- echo Deploying......
- ::remove subitems of dist
- rd /S /Q dist
- ::copy lib
- xcopy /y lib\less\img dist\lib\less\img\
- ::copy html files
- xcopy /y src\*.html dist\app\
- ::compile less to css
- cmd /C lessc --include-path=lib/less --clean-css="advanced" --relative-urls src/less/main.less dist/app/style/main.css
- echo Deploying is over!
- :over
然后在CMD中输入 build bin 、 build debug 或 build dist 即可构建工程了!
九、与Grunt结合
我们沿用第八节的工程目录结构来演示。
首先我们要将npm的package.json添加到工程中,然后安装grunt及其插件(grunt-contrib-less,less-plugin-clean-css,grunt-contrib-clean,grunt-contrib-copy),现在我们的工程结构应该是这样的。
sample-grunt
|-- package.json
|-- Gruntfile.js
|-- node_modules
|-- lib 第三方依赖库
| |-- less
| |-- base.less
| |-- img
| |-- nav.png
|-- 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
其中用于将Less编译为CSS的插件为grunt-contrib-less, 下面我们对应第八章的内容来介绍该插件的选项。
sourcemap相关:
{Boolean} sourceMap,对应lessc中属性值为true/false的--source-map选项;
{String} sourceMapFilename,对应lessc中属性值为String的--source-map选项;
{String} sourceMapRootPath,对应lessc的--source-map-rootpath选项;
{String} sourceMapURL,对应lessc的--source-map-url选项;
{Boolean} outputSourceFiles,,对应lessc的--source-map-map-inline选项;
@import指令相关:
{Array|String} paths,对应lessc的--include-path选项;
{Boolean} relativeUrls,对应lessc的--relative-urls选项;
插件相关:
{Array} plugins,数组元素为插件实例。
Gruntfile.js内容如下:
- 'use strict'
- var lessBinDebugOpts = {
- sourceMap: true,
- sourceMapRootpath: '../../'
- },
- debug = {env: 'debug'}
- module.exports = function(grunt){
- grunt.initConfig({
- clean: {
- options:{
- force: true
- },
- bin: ['bin'],
- dist: ['dist']
- },
- copy: {
- bin: {
- files: [
- {expand: true, cwd: 'src/', src: '*.html', dest: 'bin/'}
- ]
- },
- dist: {
- files:[
- {expand: true, cwd: 'lib/', src: '**', dest: 'dist/lib/'},
- {expand: true, cwd: 'src/', src: '*.html', dest: 'dist/app'}
- ]
- }
- },
- less: {
- options:{
- paths: 'lib/less',
- relativeUrls: true
- },
- bin:{
- options: (delete lessBinDebugOpts.modifyVars, lessBinDebugOpts),
- files: {
- 'bin/style/main.css': 'src/less/main.less'
- }
- },
- debug:{
- options: (lessBinDebugOpts.modifyVars = debug, lessBinDebugOpts),
- files: {
- 'bin/style/main.css': 'src/less/main.less'
- }
- },
- dist:{
- options:{
- plugins: [new (require('less-plugin-clean-css'))({advanced: true})]
- },
- files: {
- 'dist/app/style/main.css': 'src/less/main.less'
- }
- }
- }
- })
- grunt.loadNpmTasks('grunt-contrib-less')
- grunt.loadNpmTasks('grunt-contrib-copy')
- grunt.loadNpmTasks('grunt-contrib-clean')
- var task = function(){
- var name = this.name
- , tasks = ['clean', 'copy', 'less']
- , targets = tasks.map(function(v, i, m){
- var target = name === 'debug' && v !== 'less' ? 'bin' : name
- return v + ':' + target
- })
- grunt.task.run(targets)
- }
- grunt.registerTask('bin', task)
- grunt.registerTask('debug', task)
- grunt.registerTask('dist', task)
- }
十、总结
到这里我只能和大家说一声,“辛苦了各位,终于看完了耶!”。但正如标题所说,此刻无论是对less的使用,还是将其融入我们的开发工作流,我们均是入了个门而已。那应该如何进阶呢?那就是
- ;; 定义进阶过程
- (defn becomeGeek [progress]
- (.log js/console "实践->总结->参考最佳实践")
- (if (> progress)
- (becomeGeek (+ progress))
- ))
- ;; 努力吧骚年!
- (becomeGeek )
尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/4187675.html ^_^肥仔John!
前端构建:Less入了个门的更多相关文章
- 前端构建:Source Maps详解
一.前言 当使用CoffeeScript.ClojureScript编写前端脚本时,当使用Less.Sacc编写样式规则时,是否觉得调试时无法准确找到源码位置呢?当使用jquery.min.js等经压 ...
- 前端构建工具gulpjs的使用介绍及技巧
gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简单,学习起来很容易,而且gulpjs使用的是nodejs中stream来读取和操作数据,其速 ...
- 前端构建工具gulp使用
前端自动化流程工具,用来合并文件,压缩等. Gulp官网 http://gulpjs.com/ Gulp中文网 http://www.gulpjs.com.cn/ Gulp中文文档 https://g ...
- 前端构建工具gulp介绍
2016年3月3日 10:46:08 晴 前端构建工具gulpjs的使用介绍及技巧 gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简 ...
- 前端构建工具gulpjs
gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简单,学习起来很容易,而且gulpjs使用的是nodejs中stream来读取和操作数据,其速 ...
- (转载)前端构建工具gulp使用
前端构建工具gulp使用 前端自动化流程工具,用来合并文件,压缩等. Gulp官网 http://gulpjs.com/ Gulp中文网 http://www.gulpjs.com.cn/ Gulp中 ...
- 前端构建工具gulp
前端构建工具gulp使用 前端自动化流程工具,用来合并文件,压缩等. Gulp官网 http://gulpjs.com/ Gulp中文网 http://www.gulpjs.com.cn/ Gul ...
- [转载]前端构建工具gulpjs的使用介绍及技巧
转载地址:http://www.cnblogs.com/2050/p/4198792.html gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非 ...
- 前端构建工具之gulp的安装和配置
在选择构建工具时,看到更多人推荐gulp,从此入了gulp的坑- 一.安装node环境 百度谷歌一下就有了,在终端中分别输入 node -v 和 npm -v,若显示node和npm的版本号则说明no ...
随机推荐
- 不写1行代码,在Mac上体验ASP.NET 5的最简单方法
昨天微软发布了ASP.NET 5 beta2(详见ASP.NET 5 Beta2 发布),对ASP.NET 5的好奇心又被激发了. 今天下午在Mac OS X上体验了一下ASP.NET 5,而且借助Y ...
- Linux系统中如何挂载第二块硬盘
一.检测硬盘能否被识别 # fdisk -l Disk /dev/sda: 36.7 GB, 36703934464 bytes 255 heads, 63 sectors/track, 4462 c ...
- Linux 网络编程(TCP)
客户端代码 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/sock ...
- 让gcc支持成员函数模板的trick
让gcc支持成员函数模板的trick 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循“署名-非商业用途-保持一致”创作公用协议 gcc 4.7.3 不支持成员 ...
- ueditor上传大容量视频报http请求错误的解决方法
故障现象: 当使用百度编辑器ueditor上传大容量视频或大容量图片的时候,编辑器报"http请求错误"的解决方法详解: 原因分析: 目前很多CMS整合了百度的ueditor编辑器 ...
- 厚积薄发,拥抱 .NET 2016
厚积薄发这个词是高三英语老师在高考前写在黑板上,高中三年努力这么久,是时候迎面而上,冲刺向前.所以,一想到.NET 2016,脑海里蹦出的第一个词就是它. .NET 2016 是 .NET 一次质的飞 ...
- redis配置文件redis.conf中文版(基于2.4)
转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/99.html?1455869981 代码如下: # Redis示例配置文件 ...
- 谈谈设计模式~原型模式(Prototype)
返回目录 原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例(clone),而不是新建(new)实例.被复制的实例就是我们所称的“原型”,这个原型是可定制的. 原型模式 ...
- WebKit技术内幕
WebKit技术内幕(浏览器内核|渲染引擎| HTML5| Chromium项目Committer重磅作品) 朱永盛 著 ISBN 978-7-121-22964-0 2014年6月出版 定价:7 ...
- 批处理集锦——(4)2>nul和1>nul是什么意思?
>nul 是屏蔽操作成功显示的信息,但是出错还是会显示(即1>nul) 2>nul 是屏蔽操作失败显示的信息,如果成功依旧显示. >nul 2>nul 就是正确的错误的一 ...