目标
掌握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; }