Jacleklm's Blog

CSS Modules

2020/04/30

简介

CSS Modules 不同于 less,sass 等,不是把CSS改造成编程语言,而是功能很单纯,只加入了局部作用域和模块依赖

解决的问题

  • 全局样式冲突(主要问题)
  • css选择器嵌套过深,有性能问题
  • 代码冗余(无继承)
  • 模块化

局部作用域

CSS的规则都是全局的,任何一个组件的样式规则,都对整个页面有效。这使得在开发中很可能有类名相同造成相互影响的情况,多层嵌套css又会造成性能问题。

产生局部作用域的唯一方法,就是使用一个独一无二的class的名字,不会与其他选择器重名。这就是 CSS Modules 的做法

基本写法

一个React组件App.js。

1
2
3
4
5
6
7
8
9
10
import React from 'react';
import style from './App.css';

export default () => {
return (
<h1 className={style.title}>
Hello World
</h1>
);
};

App.css

1
2
3
4
5
6
7
8
9
.title {
color: red;
}
// 这种写法等于:
:local {
.title {
color: red;
}
}

构建工具会将类名style.title编译成一个哈希字符串。

1
2
3
<h1 class="_3zyde4l1yATCOkgn-DBWEL">
Hello World
</h1>

App.css也会同时被编译。

1
2
3
._3zyde4l1yATCOkgn-DBWEL {
color: red;
}

webpack的支持

要开启 CSS Modules 功能,在webpack的loader配置中要有:

1
2
3
4
{
test: /\.css$/,
loader: "style-loader!css-loader?modules"
},

style-loader!css-loader?modules,它在css-loader后面加了一个查询参数 modules,表示打开 CSS Modules 功能
与 sass, less 联用时同理

全局作用域

允许使用:global(.className)的语法,声明一个全局规则。凡是这样声明的class,都不会被编译成哈希字符串,而是保留类名
css:

1
2
3
4
5
6
7
8
9
10
11
12
13
.title {
color: red;
}

:global(.title) {
color: green;
}
// 更常用的写法:
:global {
.title {
color: green;
}
}

js:

1
2
// ...
<div className="title">Hello World!<div>

结果会是 green

定制哈希类名

css-loader默认的哈希算法是[hash:base64],这会将.title编译成._3zyde4l1yATCOkgn-DBWEL这样的字符串。

webpack.config.js里面可以定制哈希字符串的格式。

1
2
3
4
5
6
7
8
9
module: {
loaders: [
// ...
{
test: /\.css$/,
loader: "style-loader!css-loader?modules&localIdentName=[path][name]---[local]---[hash:base64:5]"
},
]
}

你会发现.title被编译成了demo03-components-App---title---GpMto

一些技巧

组合 composition

在App.css中,让.title继承 .className 。

1
2
3
4
5
6
7
.className {
background-color: blue;
}
.title {
composes: className;
color: red;
}

输入其他模块

选择器也可以继承其他CSS文件里面的规则。
another.css:

1
2
3
.className {
background-color: blue;
}

App.css可以继承another.css里面的规则。

1
2
3
4
.title {
composes: className from './another.css';
color: red;
}

变量

这些和 less,sass 等联合使用

关于样式覆盖问题

因为CSS Modules 不会覆盖属性选择器,所以可以利用属性选择器来解决这个问题
// 组件中

1
2
3
4
5
return (
<div data-role='test'>
测试
</div>
)

// 样式

1
2
3
[data-role="test"] {
color: red;
}

参考资料
阮一峰
博客园
掘金

1

CATALOG
  1. 1. 简介
    1. 1.1. 解决的问题
  2. 2. 局部作用域
    1. 2.1. 基本写法
    2. 2.2. webpack的支持
  3. 3. 全局作用域
  4. 4. 定制哈希类名
  5. 5. 一些技巧
    1. 5.1. 组合 composition
    2. 5.2. 输入其他模块
    3. 5.3. 变量
    4. 5.4. 关于样式覆盖问题