写在前面
原本很早之前就想写这个文章,但是因为种种原因写了一半,一直放在也草稿箱里面。现在正好是大年三十的前一天,闲来无事刚好有时间把这个补全一下。
CSS Modules顾名思义就是CSS模块化的意思,模块化和面向对象的思想之前一直无法很好的作用的css上,导致了样式的覆盖,从而影响了本身的效果。随着OOCSS和BEM等理论的提出以及预编译语言less、sass和PostCSS的出现,css开始变得多样化。CSS Modules语法可以说相对比较简单,是可以脱离这些预编译语言来使用,也可以单独来使用。
一、主要技术栈介绍
本文主要使用到技术主要包括:
- React
- Webpack
- CSS Modules
本文所述代码已经同步到github上,是基于之前写的一个react的模版工程react-webpack-boilerplate进行的,并在之上做了优化。
二、基本使用
首先在webpack上进行配置启用CSS Modules:
{
test: /\.css$/,
loaders: [
'style-loader',
'css-loader?modules'
}
接着创建一个modules.css
的文件,内容为:
.color {
color: red;
}
接下来使用这个样式,在index.jsx
中:
// 整体引入
import modules from './modules.css'
// 按需引入
import { color } from './modules.css'
可以将所有的类一次性都引入,也可以按需引入
不同引入方式的使用方式如下:
class Cssmodules extends React.Component {
render() {
return (
<div>
<h1>基本用法</h1>
<p className={modules.color}>这是整体引入的红色文字</p>
<p className={color}>这是通过按需引入红色文字</p>
</div>
)
}
}
最后的显示就是这样:
三、作用域
作用域分两种:局部(:local
)和全局(:global
)。像上面那样不管是modules.color
还是color
都属于局部作用,这时候可以用浏览器去看一下在上一步生成的html中类名,是这样的:
这里会变成一个唯一的hash字符串,只在当前作用域有效,在其他页面使用这个类名是无效的,这也是css模块化的一种体现。当然也可以显示的声明一个局部的类名,与上面是一样的,就像这样:
:local(.color) {
color: red;
}
如果想要定义全局的样式,使用:global
,在modules.css
中加入下面代码:
:global(.global-color) {
color: green;
}
全局定义的样式与我们之前写的是一样的,直接使用类名,最后生成的类名也不会改变,在index.jsx
中使用:
<p className="global-color">这是通过:global定义的绿色文字</p>
当然,在编译以后类名也不会改变:
四、组合
CSS Modules中的组合类似于less和sass中的混合(Mixins),不同的是less中直接使用另一个类名,而在sass中是通过@mixin
和@include
这两个关键字实现,那么在CSS Modules中也有一个composes
。
1.基本使用
在modules.css
中新增一个样式并使用:
.bg-color {
background-color: black;
}
.composes {
/* 这里可以组合多个类 如:composes: bg-color bg1 bg2; */
composes: bg-color;
color: #fff;
}
这里并不是将设置背景颜色的代码放入了.composes
中,而是使用这两个类,这一点可以从编译之后的代码中发现:
从上图可以看出是使用了两个类名,分别是
.composes
和.bg-color
转成的hash字符串,有兴趣可以分别使用这两个类看一下。
2.使用其他css文件
组合还可以使用其他的css文件,这里新建一个other.css
的文件,写入下面修设置字体类型的样式:
.ff {
font-family: Arial, Helvetica, sans-serif;
}
仍然使用composes
:
.composes {
composes: bg-color;
composes: ff from './other.css';
color: #fff;
}
3.组合使用全局样式
同样,在modules.css
中加入修改字体粗细的样式:
:global(.fw) {
font-weight: 400
}
在使用的时候:
.composes {
composes: bg-color;
composes: ff from './other.css';
composes: fw from global;
color: #fff;
}
最后在编译之后的结果是,三个局部的类一个全局的类.fw
:
五、与less和sass配合使用
与less和sass配合使用的方法是一样的,这里只说一下less,sass的在代码里面有。
首先安装相关依赖less-loader
、sass-loader
和node-sass
等,并修改webpack配置:
// ...
{
test: /\.less$/,
loader: 'style-loader!css-loader?modules!less-loader'
},
{
test: /\.scss$/,
loader: 'style-loader!css-loader?modules!sass-loader'
},
// ...
然后,新建一个less-modules.less
的文件,在less中定义类是这样的:
:global {
.less-color {
color: pink;
}
}
:local {
.less-font-size {
font-size: 20px;
}
}
接下来就是一样的:
import lessModules from './less-modules.less'
// ...
<p className="less-color">这是通过less设置的:global字体颜色为粉色</p>
<p className={lessModules['less-font-size']}>这是通过less设置的:local字体大小为20px</p>
// ...
六、自定义类名
从上面的也看出来,所谓的hash字符串的可读性不是很高,所以我们有时候需要自定义类名来修改原始生成的类名。
这种自定义类名只限于局部作用域的类名,对于全局作用域是不起作用的。
css-loader提供了一个localIdentName
参数,同时我们还可以利用这四个参数path
、name
、local
和hash
,四个参数的含义依次是:当前css、less或sass的文件路径,引入的模块名,局部作用域的类名,独一无二的hash值。
下面我在less的webpack配置中做如下修改:
// ...
{
test: /\.less$/,
loader: 'style-loader!css-loader?modules&localIdentName=[path]_[name]__[local]___[hash:base64:5]!less-loader'
},
// ...
编译之后类名为:
配合之前在
less-modules.less
中添加的代码,path
、name
和local
一目了然,
[hash:base64:5]
表示取hash值的前五位。
写在后面
对于CSS Modules的语法相对来比较简单,相信如果有一点css基础的只要看一遍使用起来都不会有太大的问题。
在写之前我就在想现在less、sass和PostCSS已经大行其道的今天,CSS Modules还有没有更多的空间,但是其中模块化的思想来区分局部作用域和全局作用域还是很有用的,所以想来想去还是写一下,虽然理解的可能不深,但……谁还不是小仙女咋的!
注:
今天是2018年2月14日
Happy Valentine's Day
冷落了小仙女,不说了,我要去买新键盘了( >﹏<。)~