less
变量(Variables)
@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;
#header { color: @light-blue; }
编译为:
#header {
color: #6c94be;
}
混合(Mixins)
.bordered { border-top: dotted 1px black; border-bottom: solid 2px black; }
#menu a { color: #111; .bordered; }
.post a { color: red; .bordered; }
再举几个栗子:
.a, #b { color: red; }
.mixin-class { .a(); }
.mixin-id { #b(); }
注意其中的.a()和#b(),用.a和#b来是一样的效果。两种等效。
经典应用
又想创造一个类又不想让他输出,只想让它被别的用的时候********后面加个()
.my-mixin { color: black; }
.my-other-mixin() { //注意这里多了个()是关键,表示不单独输出这个,但是其他的还是可 //以使用这个
background: white;
}
.class { .my-mixin; .my-other-mixin; }
输出结果:里面并不含 .my-other-mixin 这个单独的类
.my-mixin { color: black; }
.class { color: black; background: white; }
选择器中的插入混合
.my-hover-mixin() {
&:hover { border: 1px solid red; }
}
button { .my-hover-mixin(); }
输出:
button:hover { border: 1px solid red; }
定义一个hover效果,在别的类中插入,就可以获得类的hover效果。
命名空间
如果您想要在一个更复杂的选择器中混合属性,您可以堆叠多个id或类。
#outer {
.inner { color: red; }
}
只想用.Inner
.c { #outer > .inner; }
大概意思就是你想用某个大的属性中的某个小的属性,就可以通过堆叠的方式来进行,类似css中的选择
有条件的类名
效果类似如下:
#namespace when (@mode=huge) {
.mixin() { /* */ }
}
#namespace {
.mixin() when (@mode=huge) { /* */ }
}
想要了解更多可以查看api文档
!important 关键字
用法如下:
.foo (@bg: #f5f5f5, @color: #900) {
background: @bg;
color: @color;
}
.unimportant {
.foo();
}
.important {
.foo() !important;
}
输出:
.unimportant {
background: #f5f5f5;
color: #900;
}
.important {
background: #f5f5f5 !important;
color: #900 !important;
}
传参的插入混合
定义一个:
.border-radius(@radius) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
border-radius: @radius;
}
定义完了以后用法--->
#header {
.border-radius(4px);
}
.button {
.border-radius(6px);
}
定义的时候也可以给定默认值
.border-radius(@radius: 5px) {
-webkit-border-radius: @radius;
-moz-border-radius:
@radius; border-radius: @radius;
}
然后可以这么调用
#header { .border-radius; }
多个参数的插入和混合
.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;
}
这里有个问题: 为什么输出到color-2 当参数是两个的时候,从2输出到3,三个参数的时候只输出3.
多个参数也可以提前赋值
举个栗子:
.mixin(@color: black; @margin: 10px; @padding: 20px) {
color: @color;
margin: @margin;
padding: @padding;
}
.class1 {
.mixin(@margin: 20px; @color: #33acfe);
}
.class2 {
.mixin(#efca44; @padding: 40px);
}
可以看到赋值不用管顺序,而且可以先赋值
输出
.class1 {
color: #33acfe;
margin: 20px; padding: 20px;
}
.class2 {
color: #efca44;
margin: 10px;
padding: 40px;
}
参数数组变量@arguments
.box-shadow(@x: 0; @y: 0; @blur: 1px; @color: #000) {
-webkit-box-shadow: @arguments;
-moz-box-shadow: @arguments;
box-shadow: @arguments;
}
.big-block {
.box-shadow(2px; 5px);//直接传入参数组
}
输出结果
.big-block {
-webkit-box-shadow: 2px 5px 1px #000;
-moz-box-shadow: 2px 5px 1px #000;
box-shadow: 2px 5px 1px #000;
}
可变参数数量的使用
.mixin(...) { // matches 0-N arguments
.mixin() { // matches exactly 0 arguments
.mixin(@a: 1) { // matches 0-1 arguments
.mixin(@a: 1; ...) { // matches 0-N arguments
.mixin(@a; ...) { // matches 1-N arguments
或者:
.mixin(@a; @rest...) {
// @rest is bound to arguments after @a
// @arguments is bound to all arguments
}
通过以上都可以获得一个参数可变的声明类
根据传递的参数改变混合的行为(类似函数)
.mixin(@s; @color) { ... }
.class {
.mixin(@switch; #888);
}
定义.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); }
输出的结果会是
.class {
color: #a2a2a2; display: block;
}
中间的判断过程大概是
第一个mixin定义不匹配,因为它期望第一个参数为dark。
第二个mixin定义匹配,因为它期望第一个参数是light。
第三个mixin定义匹配,因为它期望第一个参数都可以。
也就是说参数匹配的才可以执行(完全的函数思路)
也可以通过参数数量来进行匹配
.mixin(@a) { color: @a; }
.mixin(@a; @b) { color: fade(@a; @b); }
传一个参数就匹配一个的,传两个参数就匹配两个的
类似函数的混合
在mixin中定义的变量和mixin是可见的,可以在调用者的范围中使用。只有一个例外,如果调用者包含同名的变量(包含由另一个mixin调用定义的变量),则不会复制变量。只有在调用者本地范围内的变量才被保护。从父作用域继承的变量被重写。
.mixin() {
@width: 100%;
@height: 200px;
}
.caller {
.mixin();
width: @width;
height: @height;
}
输出结果
.caller {
width: 100%;
height: 200px;
}
调用完.mixin以后,里面的值会作为返回值返回,这就使得我们能像使用函数一样使用。
在来个栗子:
.average(@x, @y) {
@average: ((@x + @y) / 2);
}
div {
.average(16px, 50px); // "call" the mixin
padding: @average; // use its "return" value
}
在调用方范围中直接定义的变量不能被覆盖。但是,在调用方的父范围中定义的变量不受保护,并且将被覆盖:
举个栗子:
.mixin() {
@size: in-mixin;
@definedOnlyInMixin: in-mixin;
}
.class {
margin: @size @definedOnlyInMixin;
.mixin();
}
@size: globaly-defined-value; // 全局定义的 父级的不受保护
输出结果: 全局定义的在。Class内被局部的覆盖了
.class {
margin: in-mixin in-mixin;
}
多层嵌套的依旧会作为返回值
.unlock(@value) { // 外部mixin
.doSomething() { // 嵌套的mixin
declaration: @value;
}
}
#namespace {
.unlock(5); // unlock doSomething mixin
.doSomething(); //nested mixin was copied here and is usable(可用的)
}
输出:
#namespace {
declaration: 5;
}
大概流程: .unlock(5) 给doSomething的@value 传了一个值
.doSomething(); 又调用这个函数 并使用了返回值 declaration: @value;
嵌套(Nesting)
#header { color: black; }
#header .navigation { font-size: 12px; }
#header .logo { width: 300px; }
可写为
#header { color: black; .navigation { font-size: 12px; } .logo { width: 300px; } }
.clearfix {
display: block; zoom: 1;
&:after { content: " ";
display: block; font-size: 0;
height: 0;
clear: both;
visibility: hidden; }
}
& represents the current selector parent &表示的是当前选择的父级
运算(Operations)
@conversion-1: 5cm + 10mm; // result is 6cm
@conversion-2: 2 - 3cm - 5mm; // result is -1.5cm // conversion is impossible @incompatible-units: 2 + 5px - 3cm; // result is 4px // example with variables @base: 5%; @filler: @base * 2; // result is 10%
@other: @base + @filler; // result is 15%
Escaping(中文是转义字符)
Escaping allows you to use any arbitrary string as property or variable value. Anything inside ~"anything" or ~'anything' is used as is with no changes except interpolation.
转义允许您使用任意字符串作为属性或变量值。~“任何东西”或“任何东西”~的任何东西除了插值之外没有任何变化。
@min768: ~"(min-width: 768px)";
.element {
@media @min768 {
font-size: 1.2rem;
}
}
编译为:
@media (min-width: 768px) {
.element {
font-size: 1.2rem;
}
}
函数(Functions)
例子将介绍如何利用 percentage 函数将 0.5 转换为 50%,将颜色饱和度增加 5%,以及颜色亮度降低 25% 并且色相值增加 8 等用法:
@base: #f04615;
@width: 0.5;
.class {
width: percentage(@width); // returns `50%`
color: saturate(@base, 5%);
}
Namespaces and Accessors
(作用类似于封装)
#bundle() {
.button {
display: block;
border: 1px solid black;
background-color: grey;
&:hover {
background-color: white
}
}
.tab { ... }
.citation { ... }
}
可写为
#header a {
color: orange;
#bundle > .button; // can also be written as #bundle.button
}
作用域(Scope)
@var: red;
#page {
@var: white;
#header {
color: @var; // white
}
}
@var: red;
#page {
#header {
color: @var; // white
}
@var: white;
}
用距离最近的作用域内的值
注释(Comments)
块注释和行注释都可以使用:
/* 一个块注释 * style comment! */
@var: red;
// 这一行被注释掉了!
@var: white;
导入(Importing)
“导入”的工作方式和你预期的一样。你可以导入一个 .less 文件,此文件中的所有变量就可以全部使用了。如果导入的文件是 .less 扩展名,则可以将扩展名省略掉:
@import "library";
// library.less
@import "typo.css";
导入的顺序
在less中@import出现的位置是没有限制的,可以在进行中的位置进行导入
.foo { background: #900; }
@import "this-is-valid.less";
导入的时候还可以加一些参数进行处理
reference:使用较少的文件,但不要输出它。
inline:在输出中包含源文件,但不处理它。
less:无论文件扩展名如何,将文件视为一个更少的文件。
css:无论文件扩展名是什么,将文件作为css文件处理。
once:只包含一次文件(这是默认行为)
multiple:包含文件多次。
optional:在未找到文件时继续编译。
举个栗子:
@import (optional, reference) "foo.less";
具体每个参数的详细效果还得自己实验,看翻译看不出来 详细的英文原版在这里查找:
http://lesscss.cn/features/#import-options
安装less
命令行安装 (全局安装)
npm install less -g
为了装逼或者信息更详细你可以后面加上版本号来安装特定版本的less
npm install less@2.7.1 -g
Node中开发安装也可以
npm i less --save-dev (记住这个命令要在你所在的文件夹内的小黑框内输入)
会安装最新的版本并在你的 package.json的devDependencies 中增加版本和安装信息
lessc -v 查看你安装的版本
Less编译成css
官方栗子:
lessc [option option=parameter ...] <source> [destination]
实例
lessc bootstrap.less bootstrap.css
Less中的一些常见命令
Silent
消除错误,不再显示错误信息
lessc -s lessc --silent
Version
查看版本信息
lessc -v
lessc --version
Help
查看帮助信息
lessc --help
lessc -h
了解更多可以参考less options
浏览器中的使用
下载并引入两个关于less的css和js文件
Js是给定的,css是需要用户自己编写的
下在地址https://github.com/less/less.js/archive/master.zip
<link rel="stylesheet/less" type="text/css" href="styles.less" />
引入的less文件会被解析成css文件供你的项目使用
<script src="less.js" type="text/javascript"></script>
设置选项
<script>
less = {
env: "development",
async: false,
fileAsync: false,
poll: 1000,
functions: {},
dumpLineNumbers: "comments",
relativeUrls: false,
rootpath: ":/a.com/"
};
</script>
<script src="less.js"></script>
在引入less之前可以设置一些选项参数和函数,这样初始化的时候就会统一受到这些参数的影响。
另外一种方式就是:
<script>
less = {
env: "development"
};
</script>
<script src="less.js" data-env="development"></script>
另外一种方式:可以在script和link中用一种类似于属性的方式引入
<script src="less.js" data-poll="1000" data-relative-urls="false">
</script>
<link data-dump-line-numbers="all" data-global-vars='{ "myvar": "#ddffee", "mystr": "\"quoted\"" }' rel="stylesheet/less" type="text/css" href="less/styles.less">
Extend(延伸扩大,就是获得别的类的值的基础上自己可以扩展)
Extend语法
Extend用法举例子
nav ul {
&:extend(.inline);
background: blue;
}
.inline { color: red; }
编译后:
nav ul {
background: blue;
}
.inline,
nav ul {
color: red;
}
可以看出nav ul 获得了inline 的值并在其基础上进行了扩展,而且nav ul 在使用时 inline还没有出现(参考作用域和lazyload的解释)。
Extend 两种语法进行:
第一种:
.a:extend(.b) {
}
第二种:
.a {
&:extend(.b);
}
进阶用法:
.c:extend(.d all) {
// 这种情况下会把所有的d 包含的全部复制获得 只要是卸载d 中的一切样式
}
.c:extend(.d) {
// 这种情况就只会扩展只有 d的所有的样式
}
比如 .d{
.f{
}
}
d中含有f 当为all的时候就会把f也获取。
进阶用法2
.e:extend(.f) {}
.e:extend(.g) {}
//上面的写法太臃肿可以改为下面的 只用,分开即可
.e:extend(.f, .g) {}
选择器上的扩展
有如下的要求
必须在选择器后面扩展:
pre:hover:extend(div pre).
选择器后面和extend前面是可以有空格的
pre:hover :extend(div pre).(hover后面有一个空格)
可以实现多个扩展
pre:hover:extend(div pre):extend(.bucket tr)
上面的写法和下面的是一样的结果
pre:hover:extend(div pre, .bucket tr)
下面是错误的写法(extend必须在最后面的要求)
pre:hover:extend(div pre).nth-child(odd
集合中的扩展
pre:hover,
.some-class {
&:extend(div pre);
}
相当于给每一个都进行了扩展
pre:hover:extend(div pre),
.some-class:extend(div pre) {
}
嵌套中的扩展
栗子:
.bucket {
tr {
color: blue;
}
}
.some-class:extend(.bucket tr) {}
编译后
.bucket tr,.some-class {
color: blue;
}
不明所以但是加了个&就不一样了这个&应该是一种用法
栗子:
.bucket {
tr & {
color: blue;
}
}
.some-class:extend(tr .bucket) {}
编译后
tr .bucket,.some-class {
color: blue;
}
扩展的准确性
.a.class,
.class.a,
.class > .a {
color: blue;
}
.test:extend(.class) {} // 这个不会匹配上面的任何一个
*.class { color: blue; }
.noStar:extend(.class) {}
输出结果
*.class { color: blue; }
//*.class 和.class的效果是一样的没有区别但是会导致扩展无法识别
顺序也会影响
link:hover:visited {
color: blue;
}
.selector:extend(link:visited:hover) {} //顺序改变了extend不会识别
输出
link:hover:visited {
color: blue;
}
Nth的效果
虽然css中的iN+3 和N+3基本一样,但是extend却无法识别
:nth-child(1n+3) {
color: blue;
}
.child:extend(:nth-child(n+3)) {}//换成了n+3 因此下面无法识别
输出:
nth-child(1n+3) {
color: blue;
}
属性key-value值的效果
[title=identifier] {
color: blue;
}
[title='identifier'] {
color: blue;
}
[title="identifier"] {
color: blue;
}
以上三种都是可以被识别的 三个的效果是一样的可以互通
.noQuote:extend([title=identifier]){}
.singleQuote:extend([title='identifier']) {}
.doubleQuote:extend([title="identifier"]) {}
输出
[title=identifier],.noQuote,.singleQuote,.doubleQuote {
color: blue;
}
[title='identifier'],.noQuote,.singleQuote,.doubleQuote {
color: blue;
}
[title="identifier"],.noQuote,.singleQuote,.doubleQuote {
color: blue;
}
All
进阶用法中已经介绍
Extend 不能识别含有变量的,它会自动忽略
@variable: .bucket;
@{variable} {
// interpolated selector color: blue; }
.some-class:extend(.bucket) {} // 什么都不会做,不会匹配
下面的额方式依然还是不会被识别
.bucket {
color: blue;
}
.some-class:extend(@{variable}) {} // interpolated selector matches nothing @variable: .bucket;
媒体查询中的扩展
在媒体声明中写入的扩展应该只匹配同一媒体声明中的选择器:
@media print {
.screenClass:extend(.selector) {} // 在媒体查询中扩展
.selector { // 同一个媒体查询中的才会被匹配
color: black;
}
}
.selector { //这个不会被匹配
color: red;
}
@media screen {
.selector { //不是同一个media也不会被匹配
color: blue;
}
}
输出:
@media print {
.selector,
.screenClass {
color: black;
}
}
.selector {
color: red;
}
@media screen {
.selector {
color: blue;
}
}
在媒体声明中写入的扩展不匹配嵌套中的选择器。
栗子:
@media screen {
.screenClass:extend(.selector) {} // extend inside media
@media (min-width: 1023px) {
.selector { // ruleset inside nested media - extend ignores it
color: blue;
}
}
}
输出:
@media screen and (min-width: 1023px) {
.selector { /* ruleset inside another nested media was ignored */
color: blue;
}
}
顶级扩展匹配所有内容,包括嵌套媒体中的选择器:不名所以,貌似是@media screen是全局的所以extend是可以用的
@media screen {
.selector { /* ruleset inside nested media - top level extend works */
color: blue;
}
@media (min-width: 1023px) {
.selector { /* ruleset inside nested media - top level extend works */
color: blue;
}
}
}
.topLevel:extend(.selector) {} /* top level extend matches everything */
输出:
@media screen {
.selector,
.topLevel { /* ruleset inside media was extended */
color: blue;
}
}
@media screen and (min-width: 1023px) {
.selector,
.topLevel { /* ruleset inside nested media was extended */
color: blue;
}
}
Duplication Detection(重复检测)
Currently there is no duplication detection.
栗子:
.alert-info,.widget {
/* declarations */
}
.alert:extend(.alert-info, .widget) {}
输出
.alert-info,.widget,.alert,.alert {
/* declarations */
//貌似是多了一个alert,但是在hbulideer中测试发现例子中的写法根本无法编译,直接报错了
}
Extend的使用情景
对于一些基础的类可以不用增加
举个栗子:
.animal {
color: white;
}
<a class="animal bear">Bear</a>
但是有这样一个标签不仅有动物的性值还有自己特殊的性值,因此你还需要给他再来个类
然后就变成这样
.animal {
color: white;
}
.bear { background-color: brown; }
这时你可以用less来进行:
<a class="bear">Bear</a> //只需要一个bear的类名就可以了
Less中的写法
.animal {
background-color: black;
color: white;
}
.bear {
&:extend(.animal);
}
这种方式类似js中的原型和继承。
其他
此外less中还有循环结构 父级选择器等 循环是很厉害但是感觉没大用