什么是cssModule
在js中,我们有大量模块化解决方案,比如es6中的export和import导入导出以及commonJS中的require以及module.export都可以实现私有变量以及全局变量。而在css中,为了实现这css的模块化,主要有下面两种方法:
- css in js。使用js或者json格式来书写样式,并将样式生成inline-style的形式,这种方式无疑可以让css拥有js的模块化功能。但是,同样缺点也十分明显,几乎无法利用css中特性,比如媒体查询,以及面对hover,active等伪类的处理比较麻烦。
- cssModule。这个方法依然使用css,但是使用js来进行状态管理,能最大化地结合现有 CSS 生态和 JavaScript 模块化能力。不过可能刚上手写起来可能有点不太习惯
传统css开发中面临的问题
- 全局污染 css中采用全局选择器的机制来设置样式,这种方式的优点是方便复用样式,缺点是可能导致需要对某些样式进行重写,必要甚至需要加上!important;
- 命名混乱 多人协作开发时,无法规范化写法,这样会导致样式冲突,选择器的写法会越来越复杂,容易形成不同的命名风格,造成混乱;
- 无法确定依赖关系 有时候我们可能只需要css文件中的一部分样式,但是一旦link一个css文件,文件会被全部加载;
- 无法共享变量 有时候可能需要js和css共享一个变量,但是显然在传统的css中无法实现;
- 压缩不够彻底 压缩工具无法对选择器进行压缩,而一般为了防止样式冲突,选择器的长度都不会太短。
使用方法
参考了阮一峰大神的《CSS Modules 用法教程》
1、局部变量
css文件的内容
.title {
color: red;
}
.test-css{
font-size:40px
}
然后在需要使用的js文件中引入css文件
在这里会输出
同时,html结构中会插入相应的内联样式
然后这样直接使用
在这里使用了一个classnames的插件,可以很方便对类名根据条件进行拼接处理。
注意 :css中test-css类名转成js之后,还是以test-css这样的名称存在
2、全局变量
如果我们想直接使用title而不是用styles.title,可以设置一个全局变量
在类名的前面加上一个:global标识就表明是一个全局变量,顺便一提,普通的默认是带上了
:local标识(可以不用写),表明局部变量。
使用时可以直接进行使用了,而不需要用styles.title
相同的样式属性,优先级高优先,优先级相同,后面的优先(无论是全局还是局部)
3、定制hash类名
css-loader中默认的类名生成规则是 [hash:base64],我们可以通过在webpack中进行配置
比如:
{
test: /\.css$/,
loader: "style-loader!css-loader?modules&localIdentName=[path][name]---[local]---[hash:base64:5]"
},
会生成
其中各个部分对应为:
- demo03-components-app对应path;
- App对应name(文件名)不包含后缀;
- local对应类名,如title;
- hash:base64:5生成5位base64码
4、组合composes
cssModule中建议使用组合的方式来书写复杂样式,比如
.className {
background-color: blue;
}
.m20{
margin:20px;
padding:20px;
}
.title {
composes: className m20;
color: red;
}
其中title类名样式中包含了className和m20类名的样式,可以在title中使用composes方式进行组合,最终的编译结果为
包含三个值,分别为className,m20以及title剩余内容生成的base64。
全局变量不能使用组合
.className {
background-color: blue;
}
.m20{
margin:20px;
padding:20px;
}
.title {
composes: className m20;
color: red;
}
:global(.all){
composes: title;
}
表示组合只允许在 单个的局部选择器 上。
5、引入其它模块
可以在compose中引入其它css中的变量
//app.css
.title {
composes: className from './another.css';
color: red;
}
//another.css
.className {
background-color: blue;
}
.another{
font-size:30px;
}
引入文件之后,会将外部文件中的内容全部引入
可以看见,我们只使用了className,但是将another也一起进行了编译
总结
总结一下,使用cssModule尽量遵循以下原则
- 不使用选择器,只使用class名来定义样式;
- 不层叠样式,只使用一个类名把样式定义好;
- 不嵌套,尽量使用组合的方式定义样式