前段时间在阅读 ant-design-pro 的源码时,发现了一种没见过的 CSS 书写方法,它能有效地解决 class 命名重复的问题。后面通过 Google 得知这是 CSS Modules,它能为 CSS 提供默认的局部作用域。
基本使用
CSS Modules 使用起来十分简单,它支持多种构建工具,这里以我在一个 React 项目中的实际使用为例进行说明。
在构建项目时使用的是 create-react-app
脚手架,通过 react-app-rewired 进行配置的修改。通过 css-loader 支持 CSS Modules,对应的 webpack 配置如下:
{
loader: require.resolve('css-loader'),
options: {
modules: true,
importLoaders: 1,
localIdentName: '[local]___[hash:base64:5]'
}
}
css-loader 内置了 CSS Modules,设置 modules 参数为 true
即可启用。
配置好了 CSS Modules 之后,在代码中通过下面的方式书写样式:
// 导入样式样式文件
import styles from './BasicLayout.scss';
return (
// 导入的 styles 类似对象一样使用,将 className 作为 key
<div className={styles.logo}>
<h1>后台管理系统</h1>
</div>
);
最后,渲染出来的效果如下图所示(戳原文查看图片)。
全局作用域
CSS Modules 为 CSS 提供了局部作用域,但是有时候确实需要定义一些全局的样式,这时候该怎么办呢?
CSS Modules 允许使用 :global(.className)
的语法,声明一个全局规则。凡是这样声明的 class,都不会被编译成哈希字符串。如果需要声明多个全局规则,可以使用下面这种方式:
:global {
.clearfix {
zoom: 1;
}
.clearfix:after, .clearfix:before {
content: " ";
display: table
}
.clearfix:after {
clear: both;
visibility: hidden;
font-size: 0;
height: 0
}
}
自定义样式名
css-loader 默认生成的样式名是 [hash:base64]
,这会将 .title
编译成 ._3zyde4l1yATCOkgn-DBWEL
这样的字符串。我们可以通过添加 localIdentName 参数来自定义样式名的生成规则,如上面 webpack 配置中的 localIdentName: '[local]___[hash:base64:5]'
,这样 .title
就会被编译成 .title___fhba
这样的字符串。
样式复用
CSS Modules 让样式变得唯一了,那么我们要如何复用已有的样式呢?
CSS Modules 提供一个 composes 方法用于样式复用。例如,在 base.css
中有这样的一条样式:
.className {
background-color: red;
}
然后,我们可以在另外一个样式文件中这样引用它:
.title {
composes: className from './base.css';
font-size: 18px;
}
注意事项
- CSS Modules只转换 class 和 id 选择器。
- 在 js 中 styles 就像一个对象一样使用,因此如果样式名为
.site-wrapper
,那么在使用时应该写成styles['site-wrapper']
。我们可以设置 css-loader 的 camelCase 参数为true
来启动自动转换,这样在 js 中就可以通过styles.siteWrapper
使用。