前端构建 Less入门(CSS预处理器)

前端之家收集整理的这篇文章主要介绍了前端构建 Less入门(CSS预处理器)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量、混合(mixin)、函数功能,让 CSS 更易维护、方便制作主题、扩充。

Less 可以运行在 Node、浏览器和 Rhino 平台上。网上有很多第三方工具帮助你编译 Less 源码。

一、前言 

                           

说到前端构建怎能缺少CSS预处理器呢!其实CSS的预处理器有很多啦,比较出名的有Scss、Sass、Stylus和Less。(最近还听说出现了Autoprefixer等CSS后处理器,可参考@一丝的PPT)

众多CSS预处理器中Less的语法最接近原生CSS,因此相对来说更容易上手,假如有JS、C#等编程经验的话,其实上述的几种预处理器的学习成本也不会特别高。下面是我们这阵子的学习笔记,以便日后查阅。

最好的入门教程——官网地址:

最佳实践之一——Bootstrap

由于内容较多,特设目录一坨:

 

二、搭建学习环境

                       

搭建Less的学习环境非常简单,只需在标签前通过

三、内联样式和外联样式

                

基于我们现在使用的是浏览器端进行预编译,因此Less可用于内联样式和外联样式当中。

内联样式如下:

外联样式引入如下:

四、语法

 
                        

1. 注释

2. 变量(Variable)

Less中的变量有以下规则:

  1. 以@作为变量的起始标识,变量名由字母、数字、_和-组成
  2. 没有先定义后使用的规定;
  3. 可用于
  4. 定义时 "@变量名: 变量值;" 的形式;引用时采用 "@变量名" 或 "@{变量名}" 的形式;

Less源码:

.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. 以最后定义的值为最终值;

最终输出

列表类型

less变量除了支持#FFF,12px,12,test等单值类型外,还支持列表类型,通过内置函数extract通过索引获取列表元素,通过内置函数length获取列表的元素个数

最终输出:

3. 嵌套(Nested)

  Less源码:

div {   width: 100px; } .aside {   width: 200px; } }

最终输出

div { width: 100px; } .main .aside { width: 200px; }

4. 父选择器引用(ParentSelector)

  1. 采用&引用完整的父选择器

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)

有两种语法形式, :extend(){} 和 { &:extend(); }

Less源码:

:extend(){} */ .bear:extend(.animal){   width: 100px;   height: 100px; } /* 语法2:{ &:extend(); } */ .deer{   &:extend(.animal);   width: 50px;   height: 50px; }

最终输出

:extend(){} */ .bear { width: 100px; height: 100px; } /* 语法2:{ &:extend(); } */ .deer { width: 50px; height: 50px; }

注意事项:

6.1. 父选择器必须严格匹配,除了属性选择器中属性值引号不必匹配外,或添加all关键字外。 Less源码:

// 匹配成功
.son:extend(.parent [name='eyes']){}
.son:extend(
.parent [name="eyes"]){}
// all关键字会匹配所有包含parentSelector内容的选择器,并以selector替换parentSelector来生成新的选择器
// 下面的内容生成 .son,.son .hair,*.son [name=eyes]三个新的选择器
.son:extend(.parent all){}

最终输出

6.2. 父选择器不支持变量形式

Less源码:

不支持以变量作入参 .son1:extend(@{p1}){} // 形式2,不支持以变量作为选择器的规则集合 .son1:extend(.parent2){}

// 匹配成功
.son2:extend(.parent1){}
@s3: son3;
.@{s3}:extend(.parent1){}

最终输出

6.3. media query影响继承的作用域

  6.3.1. media query内的extend操作,仅能继承当前块的其他选择器样式。

注意:不能extend当前media query块内部的子media query块中的选择器样式;但可以extend父media query块的选择器样式。

  Less源码:

最终输出

6.3.2. 非media query内的extend操作,将会继承所有media query中匹配的选择器样式。

  Less源码:

最终输出

6.4. 增强的mixin定义mixin时仅能使用类选择器和ID选择器,而extend操作可对应所有的选择器,因此当没有动态入参而又需要类选择器和ID选择器以外的选择器时,可使用extend来实现mixin的功能

7. 混合(Mixin)

  Mixin相当于macro,会将样式规则内联到调用的位置中。而Less中的mixin有以下的注意点:

  7.1. 类选择器、ID选择器自动被定义为mixin,而且具有命名空间;   Less源码:

.human>#fsjohnhuang>.hair; // 或者.animal>.human>#fsjohnhuang>.hair(); // 即可调用mixin .animal.human#fsjohnhuang.hair; }

最终输出:

7.2. 显示定义不带参数和带参数的样式库(mixin库),不会输出到最终输出中,仅供调用;

  Less源码:

// 调用才会出现在最终输出
.chihuahua{
  .dog(1;2);
}

最终输出:

7.3. mixin内置两个特殊的对象 @arguments 和 @reset 。@arguments代表mixin的所有入参,而@reset代表mixin的...入参数组。

  Less源码:

.chihuahua{
  .dog(1;2;solid;1px;red);
}
.mimi{
  .cat(solid;2px;blue);
}

最终输出:

7.4. mixin的重载可定义多个同名mixin,调用时只要参数数量匹配则会执行相应的mixin。

  Less源码:

// 参数的模式匹配
// 当第一参数值为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);
}

最终输出:

8. 选择、循环作业控制

Less中通过混合(Mixin)后的when关键字来提供选择的作业控制,通过递归来实现循环的作业控制。

  Less源码:

/* 类型判断函数

  • 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));
}

最终输出

函数 * 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源码:

@success1: 1px + 2em;
.success1{
height: @success1;
}

@success2: 2px + 1em;
.success2{
height: @success2;
}

最终输出:

.success1{
height: 3px;
}

.success2{
height: 3em;
}

六、函数 

 
                            

Less为我们提供了一个功能强大的内置函数库,其中绝大部分为颜色处理函数。下面着重介绍Misc Function中的default函数、String Function中的escape函数和颜色处理函数

1. default函数

示例:

=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);
}

最终输出

虽然上述示例逻辑上不合理。但可以看出default函数用于条件控制当中,充当else或switch语句中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更复杂的功能,如下:

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 ...] [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文件的路径;

--source-map-rootpath= ,假如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文件的最后一行会插入如 /*# sourceMappingURL=main.css.map */ 的内容来指向sourcemap文件,而该选项则可修改sourceMappingURL的值。

3. @import指令相关

--include-path=[;]* ,通过@import指令引入外部less或css等文件时存在引入的文件路径到底是以哪个目录作为参考的问题,我们可以通过该选项来指定参考目录,当存在多个参考目录时,使用;号分隔。

--relative-urls 或 -ru ,用于保持样式库中的图片等资源的相对路径。示例:

不使用该选项时:

使用该选项时:

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文件内容

样式库base.less文件内容

main.less文件内容

/ 导航栏 /
.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如下:

: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内容如下:

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,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,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的使用,还是将其融入我们的开发工作流,我们均是入了个门而已。那应该如何进阶呢?那就是

总结->参考最佳实践") (if (> 100 progress) (becomeGeek (+ 1 progress)) ))

;; 努力吧骚年!
(becomeGeek 1)

猜你在找的JavaScript相关文章