共计 1790 个字符,预计需要花费 5 分钟才能阅读完成。
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]
- pathlocal
- path
- name
- local
变量
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;
}