目标
- 掌握less的基本写法
- less选择器
- 变量定义
- 掌握CSS Module技巧
Less
Less是一种CSS的预处理语言,它在CSS的基础上增加了一些编程语言的特性,可以提升我们编写CSS的效率,减少很多重复性的代码,最终编译成纯净的CSS代码执行。Less是CSS的超集,就像我们使用的TS和JS的关系,我们也可以把Less完全当作CSS来使用。
同样流行的CSS预处理器还有SCSS、Stylus,大家的基本功能都比较类似,Less因为简单易用,可以满足绝大多数的使用场景,所以我们先来学习一下它。
安装
我们可以通过 npm
来将 less
编译器安装为一个命令
npm i less -g
然后我们可以通过 lessc
命令来编译 less
文件了
lessc test.less
上面的命令会直接打印编译之后的结果,如果要输出到文件,可以加上输出文件名
lessc test.less test.css
变量(Variables)
@width: 10px;
@height: @width + 10px;
@color: #f00;
.header {
width: @witth;
height: @height;
height: @color;
}
现在CSS支持原生变量了,而且是动态的,有些时候使用原生变量会是一种更好的选择,如果需要考虑兼容性,可以使用Less的变量
混合(Mixins)
Mixin
是一种将一组属性从一个规则集混入到另一个规则集的方法。假设我们定义了一个类如下
.bordered {
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
如果我们想要在其他类中混入这些属性,只需要像函数一样调用他们即可:
.menu a {
color: #111;
.bordered();
}
.post a {
color: red;
.bordered();
}
.bordered
所包含的属性就同时出现在 .menu a
和 .post a
中了
嵌套(Nesting)
Less提供了嵌套代替层叠或者与层叠结合使用的能力,假如我们有下面的CSS代码
#header {
color: black;
}
#header .navigation {
font-size: 12px;
}
#header .logo {
width: 300px;
}
如果使用Less,我们可以这样来写
#header {
color: black;
.navigation {
font-size: 12px;
}
.logo {
width: 300px;
}
}
还可以和伪类或者子元素选择器,如
#header {
color: black;
&:hover {
color: red;
}
& > span {
font-weight: bold;
}
}
过深的嵌套只会让代码难以维护,建议嵌套不要超过三层,如果出现要嵌套超过三层的情况,应该考虑如何优化选择器的设计。
导入(Importing)
导入可以让我们将另外一个Less文件导入进来,例如我们可以把变量样式都定义在一个单独的Less模块中,其他文件都来引用它,通常我们用这种方式来控制主题样式,当我们需要修改主题的时候,只需要修改变量文件中的值,然后重新编译即可。
vars.less
@primaryColor: #f00;
@textColor: #666;
theme.less
@import "vars";
#header {
background-color: @primaryColor;
color: @textColor;
}
CSS Modules
借助于webpack,我们可以把CSS也当成模块来拆分引用了,但是模块化的一个核心是作用域隔离,CSS并没有真正的模块化机制,这意味着我们写在不同文件中的CSS代码中的类会对整个HTML页面起作用,随着我们应用中组件的增多,很容易会出现类名冲突引发样式混乱。通常我们解决这种问题需要靠命名的约定,每个模块用自己的前缀然后加上嵌套等方式,如:
.button {
}
.button-default {
}
.modal {
}
.modal-header {
}
但是这样也不安全,需要大家都自觉遵守。
现在 css-loader
提供了一种叫做 CSS Modules
的方案,可以帮我们自动生成唯一的类名,不会和其他模块的命名出现冲突
要使用CSS Modules有几个步骤,首先需要在webpack的配置文件中打开相关的配置
{
test: /\.less$/,
include: path.resolve('./src'),
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[local]-[hash:5]'
}
}
},
'less-loader'
]
}
上面配置的意思是我们对 src
下面的 .less
文件启用 modules
转换,转换的格式模板为 [local]-[hash:5]
,其中hash是根据文件名和类名确定的,所以不会冲突,因为CSS Modules会改变输出的类名,我们只能对自己写的代码进行适配。
经过上面的配置之后,我们在代码中导入的less文件返回的就是一个键值对了,其中键名是原始的类名或ID名,键值就是转换输出之后的名字,如:
{
btns: "btns-bdd41",
body: "body-dab49"
}
所以我们就不能在JSX中填写固定的类名了,需要使用变量的方式,如下
import * as React from 'react'
import style from './style.less'
export default class Main extends React.Component {
render() {
return (
<div className={style.body}>
<div className={style.btns}></div>
</div>
)
}
}
CSS Modules会转换所有的类名和ID名,如果有些名字我们不想让它转换,可以使用 :global()
,如:
:global(#app) {
background-color: #f4f4f4;
}