CSS Module
CSS Module产生背景
在软件工程里面模块指的是可组合、分解和更换的单元。下面是一张css树,项目里面总的css文件是由一系列小的单元组成,比如下面的reset.css就是一个单元。模块化的概念不光在css里面,在JS里面也是同样适用的,我们把代码按照一定的规则和逻辑拆分,分解成可组合可更换的单元,这样就实现了一个最大限度的代码复用。在css中,代码复用只是一个小的方面,更重要的是解决局部作用域的概念,也就是为了避免全局的样式污染。
index.css
├─ header.css
│ └─ reset.css
├─ content.css
│ ├─ left.css
│ │ └─ nav.css
│ └─ right.css
├─ fotter.css
└─ ...
CSS Module解决的问题
全局污染会带来一系列混乱的问题,比如在项目中已经定义了某一个元素的样式,但是现在有一个需求是这个元素的样式要重新定义,但是全局已经定义了,这个时候我们可以有几种选择:!important(加上一个important优先级)、inline(写一个行内式)或者写一个复杂度选择器。
随着项目的越来越大,越来越难以维护,就容易导致命名的混乱。
为了避免样式名的冲突,我们写的选择器也越来越复杂,然后命名也越来越长。这时如果没有一个样式的命名规范,代码将越来越难以维护。这样下去就容易导致代码的层次结构越来越不清晰。我们想要实现一个代码的复用也会也来越难。从成千上万的代码中找到自己想要复用的样式,这是有一定难度的。而且因为选择器的越来越复杂和命名越来越长导致了代码的压缩也就不彻底了,对于长的class名是无能为力的,因为要保证类名的唯一性。
综合来说就是一下几点:
-
全局污染
-
命名混乱
-
层级结构不清晰
-
代码难以复用
-
代码压缩不彻底
CSS Module 原理
主要是围绕AST语法树、Vue scoped和React Css module来介绍的。
首先介绍一下AST语法树,因为在webpack里面,我们的css还是js都会解释成AST语法树。它其实就是json的一个数据结构。
- AST语法树
{
nodes: [{
raws: {
before: '',
between: '',
semicolon: true,
after: '\r\n'
},
type: 'rule',
source: {
start: {
line: 1,
column: 1
},
input: {
css: '.header {\r\n display: flex;\r\n lost-column: 1/1;\r\n}\r\n',
hasBOM: false,
file: '../../../xiaokedao'
},
end: {
line: 4,
column: 1
}
},
selector: '.header',
lastEach: 14,
indexes: {},
nodes: []
}]
}
- Vue scoped
<div data-v-2311c06a class="button-warp"></div>
.button-warp[data-v-2311c06a]{
display: inline-block;
}
- React Css module
<div class="wrapper___2IPqp"></div>
CSS作用域
局部作用域
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{
loader: 'css-loader',
options: {
modules: true,
}
}
],
})
}
]
}
全局作用域
:global(.main) {
display: flex;
}
类组合
.header {
background: #8A469B;
}
.footer {
composes: header;
}
哈希规则
-
默认 - [hash:base64]
-
[path][name][local][hash:base64:n]
-
[path][hash:base64:n]
-
[name][hash:base64:n]
-
[local][hash:base64:n]
变量
npm install postcss-modules-values
{
loader: "postcss-loader",
"options": {
plugins: [
require('postcss-modules-values'),
]
}
}
@value color: #8A469B;
.header {
background: color;
}
.footer {
composes: header;
color: #FFF;
}