CSS在开发的时候会发现一件事,就是无法使用方法以及加入逻辑运算,这个时候就有大神发明了一门兼容CSS的扩展语言Less(Leaner Style Sheet)。
简单的说就是安装less的要求,可以使用一些编程语言中的变量,运算等,然后通过其Less样式转换工具转换为css。
其实还有SACC,Stylus,但是具体大同小异,本篇只是聊一下Less,如果有兴趣自行查询一下即可。
所以在编写less文件的时候,记得在使用的编程软件中插入less插件,本人用pycharm,所有同npm即可插入,
npm install -g less
然后再设置一下:
还可以根据自己需求设置编译后的CSS文件路径。双击less会弹出下面对话框:
路径在pycharm中生成css需要修改的话,就修改 arguments参数即可:$FileName$ $FileNameWithoutExtension$.css --source-map
修改为$FileName$ 路径\$FileNameWithoutExtension$.css --source-map
pycharm中默认会自动在文件.less下面,其实很奇怪如下:
文件即使文件又是目录?但是事实呢?
看配置路径也可以看出其生成的css文件和less文件在同一个目录下,是兄弟关系不算父子级。而pycharm只是想表达一下这个css文件时less文件自动生成的(操蛋的很)。
如果证明呢?
每个人的使用的编程工具不同,如果使用的vscode就其配置方式进行安装了,不在具体演示截图。
这样新建CSS文件的时候会如下:
一般使用的时候,通过less生成css然后再引入到html中,但是如果非要再浏览器中使用也是可以的,需要引入以下:
<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/3.11.1/less.min.js" >script>
不过一般不推荐让浏览器直接使用,毕竟如果移动过js被浏览器禁用了,那么所有的样式都不会限时。毕竟用户的环境都无法保障是可以调用自己less依托的js。
如果不适用插件编译可以使用命令
lessc 文件.less > 文件.css
变量的格式如下:
@变量名:值;
命名规范:必须有@在前面,不能包含特殊符号,不能以数字开头,其大小写是很敏感的。
选择器变量可以将选择器作为一个变量来使用,
声明的时候没有什么要注意的,但是如果作为选择器使用的话,使用的时候就需要有{}
。
@selector: #test_id;
@selectorname:testname;
@{selector}{
height: 100px;
background-color: #4a90e2;
}
.@{selectorname}{
height: 100px;
background-color: #4a90e2;
}
#@{selectorname}{
height: 100px;
background-color: #4a90e2;
}
会自动生成css文件
#test_id {
height: 100px;
background-color: #4a90e2;
}
.testname {
height: 100px;
background-color: #4a90e2;
}
#testname {
height: 100px;
background-color: #4a90e2;
}
如果不带有{}自然会报错
某些属性名字很长,为了简化可以将其定位为属性变量,方便调用。再调用到时候也需要添加{}。
演示:
@bc: background-color;
div{
@{bc}:red;
}
编译css
div {
background-color: red;
}
如果不带有{}的话虽然不会报错,但是没有效果因为不识别这个数值的名是什么。
这个方便整体修改项目地址的时候,方便修改引入的其它文件的路径,这个再调用的时候也是需要有{}的。
演示:
@rootfile: '../img';
img{
src:"@{rootfile}/1.png";
}
编译css
img {
src: "../img/1.png";
}
这个可理解将常用的属性设置赋值给变量,方便使用。不过这个需要后面加()。说着可能迷糊看代码。
@common_attribute:{background-color: #4a90e2}
div{
height: 200px;
@common_attribute();
}
编译css
div {
height: 200px;
background-color: #4a90e2;
}
其实很少声明没有多大意义的变量,在声明普通变量的的时候一般都是为了运算。比如宽度,以及可以计算的属性值。
如果使用了计算的话需要遵守一些规定。
@t_color:red;
@t_w:200px;
@t_h:800px;
@t_f:1em;
@t_color1:#55a532;
div{
width: @t_w - 10;
height: @t_h + 200em;
background-color: @t_color;
}
p{
width: @t_h*2;
font-size: (@t_w/2px);
background-color: @t_color1 - #500;
}
编译成css
div {
width: 190px;
height: 1000px;
background-color: red;
}
p {
width: 1600px;
font-size: 100px;
background-color: #00a532;
}
变量作用域最重要的准则就是就近原则
;
//可以看出其可以先定义后赋值 如果后面不没有赋值的话就会报错。
@test1:@test2;
@test2:12px;
div{
width: @test1;
@test2:5px;
height: @test3;
@test3:45px;
span{
font-size: @test3;
}
}
p{
// 这个地方无法调用test3 因为这个变量名第一次出现在其它选择器之内,而这个选择器无法得到
//width: @test3; 这里会报错
}
编译后的css
div {
width: 5px;
height: 45px;
}
div span {
font-size: 45px;
}
/*# sourceMappingURL=test.css.map */
可以看出:
毕竟在CSS中有父子关系选择器等,这个在less中也是可以也必须可以体现的。所以看一下具体如何使用。
&:表示上一层选择器的名字。其最常用的是与伪元素和伪属性一起。
@selector:p;
@{selector}:hover{
background-color: #4a90e2;
}
@{selector}::after{
content: "";
display: block;
}
@{selector}_testNane{
width: 100px;
}
div{
&:hover{
background-color: #4a90e2;
}
&::after{
content: "";
display: block;
}
&_testNane{
width: 100px;
}
}
编译成css
p:hover {
background-color: #4a90e2;
}
p::after {
content: "";
display: block;
}
p_testNane {
width: 100px;
}
div:hover {
background-color: #4a90e2;
}
div::after {
content: "";
display: block;
}
div_testNane {
width: 100px;
}
这个其实就是父类中写子类的一种方式,其实这个有点像是上面的&符,只不过这个&可以省略而已。
div{
&:hover{
background-color: #4a90e2;
}
// 这个是一个错误演示,毕竟伪属性需要贴着元素才行,虽然可以生成css,但是是无效的,对于伪元素为属性一定要带&
::after{
background-color: #4a90e2;
}
& .tessClass{
background-color: #4a90e2;
}
.tessClass{
background-color: #4a90e2;
}
}
编程生成的css
div:hover {
background-color: #4a90e2;
}
/* 这个是一个错误演示,毕竟伪属性需要贴着元素才行,虽然可以生成css,但是是无效的,对于伪元素为属性一定要带& */
div ::after {
background-color: #4a90e2;
}
div .tessClass {
background-color: #4a90e2;
}
div .tessClass {
background-color: #4a90e2;
}
@ 规则(例如 @media 或 @supports)可以与选择器以相同的方式进行嵌套。@ 规则会被放在前面,同一规则集中的其它元素的相对顺序保持不变。这叫做冒泡(bubbling)。
div{
@media screen{
// 逗号有或的意思
@media(max-width: 800px),(min-width: 1800px){
font-size: 50px;
}
@media(max-width: 900px){
font-size: 60px;
}
}
@media print{
@media (max-width: 800px) {
font-size: 45px;
}
}
}
编译css
@media screen {
}
@media screen and (max-width: 800px), screen and (min-width: 1800px) {
div {
font-size: 50px;
}
}
@media screen and (max-width: 900px) {
div {
font-size: 60px;
}
}
@media print and (max-width: 800px) {
div {
font-size: 45px;
}
}
通过less写嵌套的话,其权重考虑的时候,通过less写的就相对更加便捷一些。
方法声明有点像是声明集合,使用时候引用名字即可。声明的时候(.)和(#)都可以作为前缀
,下面演示只用(.)进行演示
演示:
//声明的时候可以带括号也可以不带,引用的时候也是可以带也可以不带
// 不过不带括号的时候,如果大意可能被人当作是类选择器,所以个人建议带上括号
.fun_tion{
font-size: 50px;
}
.fun_tion1(){
background-color: #4a90e2;
}
div{
.fun_tion();
.fun_tion1;
}
p{
.fun_tion;
.fun_tion1();;
}
编译后的css
/*不带括号,也会被当作选择器来在css中显示,所以最好带上()*/
.fun_tion {
font-size: 50px;
}
div {
font-size: 50px;
background-color: #4a90e2;
}
p {
font-size: 50px;
background-color: #4a90e2;
}
Less中可以使用默认参数,如果没有传递参数就会收纳柜默认参数。
其参数的使用有点像是JavaScript中一个arguments这个属性代表所有参数,只不过其前面有一个@,所以是@argumengs。
当然也可以取个别颜色。
演示:
#funcion_border(@a:2px,@b:solid,@c:red){
background-color: @c ;
border: @arguments;
}
div{
#funcion_border();
}
p{
#funcion_border(4px,dotted,green);
}
编译css
div {
background-color: red;
border: 2px solid red;
}
p {
background-color: green;
border: 4px dotted green;
}
有参而不是默认,如下:
#funcion_border(@a ,@b ,@c ){
background-color: @c ;
border: @arguments;
}
//div{
// #funcion_border();
//}
p{
// 因为没有默认值所以所有的参数都必须有值
#funcion_border(4px,dotted,green);
}
不过一般的时候用默认有参的次数比较多。
这个在很多语言中都有,那就是参数用(…),一般为可以赋值的复合属性传递参数,如果逻辑。
#test(...){
width: 800px;
height: 900px;
background:@arguments;
}
div{
#test(#2f3430,url("jpg/anhei.jpg"),fixed,no-repeat);
}
编译后的css
div {
width: 800px;
height: 900px;
background: #2f3430 url("jpg/anhei.jpg") fixed no-repeat;
}
这个其实又像是java中的多态了,其实这个匹配模式说起来有点不好说。还是用代码演示。
#funcion_test(@a:1px ,@b:solid ,@c:blue ){
;
border: @arguments;
}
#funcion_test(@a:12px,@b:black){
font-size:@a;
color:@b ;
}
#funcion_test(@a:red){
background-color:@a;
}
p{
#funcion_test(1px ,solid ,black );
}
div{
// 这个方法可以看出一点,那就是其所谓的个数,调用对少的不会,但是会默认调用比其参数多的(而且调用时候,如果参数多的没有默认参数值会报错)
#funcion_test(100px,pink);
}
input{
// 如果直接来一个方法名,就会生成所有带有默认参数的方法,让其合并如果重叠的话,会让后面的覆盖前面的
#funcion_test;
}
编译CSS(这个css有错误的,但是为了演示而已)
p {
border: 1px solid black;
}
div {
/* 这个地方报错,可以看出用来2个参数调用了3个参数的,但是其没有调用1个参数的 */
border: 100px pink blue;
font-size: 100px;
color: pink;
}
input {
/* 不写参数都会调用,当然也是需要有默认值的 */
border: 1px solid blue;
font-size: 12px;
color: black;
background-color: red;
}
/*# sourceMapp
所以说less中的多态没有java中那样参数和参数类型的区别。但是一般的时候不会如果上用,而是如下用:
#funcion_test(top ,@b:solid ,@c:blue ){
content: "你大爷的top";
border: 1px @b @c;
}
#funcion_test(left ,@b:solid ,@c:red ){
content: "你二大爷的left";
border: 1px @b @c;
}
#funcion_test(right ,@b:solid ,@c:green ){
content: "你三大爷的right";
border: 1px @b @c;
}
// 这个是最神奇的一个,无论调用那个都调用这个 这个一般写公共用的部分,我这个为了演示故意写了重复的
#funcion_test(@a ,@b:solid ,@c:green ){
content: "你四大爷的没有方位";
}
div{
#funcion_test(top)
}
div{
#funcion_test(right,dotted)
}
编译后CSS
div {
content: "你大爷的top";
border: 1px solid blue;
content: "你四大爷的没有方位";
}
div {
content: "你三大爷的right";
border: 1px dotted green;
content: "你四大爷的没有方位";
}
可以看出根据这种匹配的用法,就是通过简单一个方法匹配,而不需要将属性以及对应的值再重新写一遍。
这个其实本质是让方法更加规范而已,还是老规矩演示,只通过文字描述很难理解。
#test(){
background-color: #4a90e2;
.A(@a:300px){
font-size: @a;
#B(@b:red){
color: @b;
}
}
}
#C{
//#test() >.A(10px) >#B(green); //父类不能带有括号不然回报错
#test >.A >#B(green);// 这样写不会报错,
}
#D{
// 如果非要带有参数只能这样写,如果使用子方法,那么父方法必须调用,不然会报错
#test();
.A(10px);
#B(green);
}
#E{
#test();
.A(10px);
}
注释掉报错的地方,然后编译CSS。
#C {
/* 可以看出这样写,只能调用最后的方法,不会使用父类的*/
color: green;
}
#D {
background-color: #4a90e2;
font-size: 10px;
color: green;
}
注意:
首先说一下其有逻辑运算符 and ,not 和or在less中的使用也会在下面演示中体现。
#test(){
// and 运算符 判断两个条件同时满足才行
#border_class(@width,@color,@style) when (@width>5px) and (@color=#666){
border: @width @style @color;
}
// not 相当于非运算符
#backgrount_class( @color ) when not (@color=#666){
background-color: @color;
}
// 这个逗号就相当于 或运算符了
#font_class(@size)when (@size<40px) , (@size>80px) {
font-size: @size;
}
}
div{
#test > #border_class(12px,#666,dotted)
}
编译成功css
div {
border: 12px dotted #666;
}
其if的使用可以当作三目运算符的感觉。
@some: foo;
div {
margin: if((2 > 1), 0, 3px);
// iscolor 是less自带一个判断是否为颜色的方法 还有判断是否是其它类型 官网地址:https://less.bootcss.com/functions/#type-functions 这里面可以了解
color: if((iscolor(@some)), @some, black);
}
编译后是:
div {
margin: 0;
color: black;
}
注意:
.test(@n,@i:1) when (@i<=@n){
.t-@{i}{
width: (@i*100%/@n);
}
.test(@n,(@i+1));
}
.test(4);
编译的css
.t-1 {
width: 25%;
}
.t-2 {
width: 50%;
}
.t-3 {
width: 75%;
}
.t-4 {
width: 100%;
}
#test(...){
width: 800px;
height: 900px;
background:@arguments;
}
div{
#test(#2f3430,url("jpg/anhei.jpg"),fixed,no-repeat)!important;
}
编译后的css
div {
width: 800px !important;
height: 900px !important;
background: #2f3430 url("jpg/anhei.jpg") fixed no-repeat !important;
}
可以看出所有的属性后面都带有!important.
这个针对的是复合写法,而复合写法中有两种方式:
属性值之间是通过空格隔开的,连接符号用:(+_)
#test(){
// 如果这里通过连接符进行设置样式,那么下面调用的话就会分成两transform依次赋值,就不是复合赋值了
transform+_: rotate(6deg);
}
div{
#test();
transform+_: translate(10px,0px);
// 不可以这样写会报错。 #test()+_: translate(10px,0px);
}
编译后的css
div {
transform: rotate(6deg) translate(10px, 0px);
}
/*# sourceMappingURL=test.css.map */
属性值之间是通过逗号隔开的,连接符号用:(+)
#test(){
// 如果这里通过连接符进行设置样式,那么下面调用的话就会分成两transform依次赋值,就不是复合赋值了
transform+: rotate(6deg);
}
div{
#test();
transform+: translate(10px,0px);
// 不可以这样写会报错。 #test()+_: translate(10px,0px);
}
编译后css
div {
/* 这个是错误的,但是为了演示生成逗号,所以不必纠结这个出错误的样式 */
transform: rotate(6deg), translate(10px, 0px);
}
// 来一个求居中的方法
@center_width:1px;
#center_func(@father_width,@son_width){
@center_width:((@father_width - @son_width) / 2);
}
div{
#center_func(800px,40px);
margin: @center_width 0px;
}
编译后的css
div {
margin: 380px 0px;
}
虽less种有一个伪类的概念(这个是选择器而不是方法,less将选择器当作类的概念
),其可以继承,其继承是通过关键字extend。
#test{
width: 200px;
#test_son {
font-size: 12px;
}
&::after{
content: "你二大爷";
}
}
div{
&:extend(#test );
}
p{
&:extend(#test #test_son);
}
//这里可以看出对于伪元素 单独写一个继承很难实现
span{
&:extend(#test ::after);
}
看编译后的数据;
#test,
div {
width: 200px;
}
#test #test_son,
p {
font-size: 12px;
}
#test::after {
content: "你二大爷";
}
可以看出继承只能继承该选择器的属性,其子选择器不能继承如果想要继承就需要在继承中写出。就算写出也是继承的属性以及对用值,而不是将子选择器编程继承者的子选择器
如果非要继承子选择器呢?那就需要关键字all
。
#test{
width: 200px;
#test_son {
font-size: 12px;
}
&::after{
content: "你二大爷";
}
}
div{
&:extend(#test all);
}
编译后的css
#test,
div {
width: 200px;
}
#test #test_son,
/* 这里可以看出之间将子选择器也继承下来了*/
div #test_son {
font-size: 12px;
}
#test::after,
div::after {
content: "你二大爷";
}
继承也是伪类让Less中的代码可以重复使用,说一下注意点:
继承的写法(:extend()这个必须在后面,后面除了可以更:extend外不可以再有其它的)
//第一种 这样& 和 :extend 中间不可以有空格
div{
&:extend(#test all);
}
//第二种选择器 和 :extend 中间可以有空格
div :extend(#test){};
可以继承多个
div:extend(#test1):extend(#test2)
//等价于
div:extend(#test1,#test2)
说白就是导入less文件里面如果导入另一个less文件。这个使用的关键字是import。
当然还有三个连用的关键字参数:reference,once,multiple。
格式:
@import "路径/less文件名字"
//等价于
@import "路径/less文件名字".less
来一个演示:
首先来一个a.less.
#div{
background:#4a90e2;
}
再来一个b.less
@import "a";
p{
font-size: 12px;
}
查看编译后的b.css
#div {
background: #4a90e2;
}
p {
font-size: 12px;
}
这个是引入less文件,但是不会编译它,
格式:
@import ( reference) "路径/less文件名字"
//等价于
@import (reference) "路径/less文件名字".less
还是使用上面的a.less。现在再b中演示
@import (reference) "a";
p{
font-size: 12px;
}
然后看b.css
p {
font-size: 12px;
}
这个是@import默认的一种行为,相同的文件只会被导入依次,而后导入的文件的重复代码不会再被导入。
现在补充一个c.less
#div{
width: 100px;
background:#4a90e2;
}
然后b.less改为:
@import (once) "a";
@import (once) "a";
@import (once) "c";
p{
font-size: 12px;
}
编译后的css
#div {
background: #4a90e2;
}
/* 这个地方如果c.less只有一个background 也会被导入,说明文件如果是同一个包含内容和路径+文件名 */
#div {
width: 100px;
background: #4a90e2;
}
p {
font-size: 12px;
}
注意:可以看出只有导入相同路径以及相同文件名的文件才会只导入一次,个人感觉就是防止手抖然后将某一个路径下的某个文件导入多次影响性能而已。
这个和once刚好向反,而已将一个文件导入多次,所以就不再演示了。
本篇以及够多了,下一篇聊一下less自带的一些函数比如判断颜色了,判断亮度等,以及listh函数等等。