现代样式:CSS Modules

问题起源:

css的全局特性:css 全部作为全局样式的形式,容易造成命名冲突

####css 模块化的概念:

css 应该时有它的作用域的,即:

发展的过程

1.在全局作用域问题上,早期的做法:

  • OOCSS
  • BEM

都是提供一种一种方式模拟健全的作用域规则,本质上还是靠程序员自身的代码规则约束,没有在根本上解决问题。

2.webpack的出现

一切皆模块,将css也是作为模块处理

通过css-loader—local-scope实现的:

webpack配置

1
2
3
4
5
6
7
loaders: [
...
{
test: /\.css$/,
loader: 'css?localIdentName=[name]__[local]___[hash:base64:5]'
}
]

使用方式:

引入:

1
import styles from './MyComponent.css';

css文件:

1
2
3
4
5
6
:local(.foo){
color: red;
}
:local(.bar){
color:blue;
}

编译成:

1
.MyComponent__foo___1rJwx { … }

很明显,:local 表示在局部作用域中使用的类名

在使用css的地方这样写:

1
2
3
4
5
6
7
8
9
10
11
12
import styles from './MyComponent.css';
import React, { Component } from 'react';
export default class MyComponent extends Component {
render() {
return (
<div>
<div className={styles.foo}>Foo</div>
<div className={styles.bar}>Bar</div>
</div>
);
}
}

这样:不用在所有的类名添加冗长的前缀来模拟范围,多个组件可以自定义自己的foo和bar标识符,可以大胆修改我们的CSS,不用小心翼翼地怕影响其他页面的元素

重大的突破:

编写可维护的CSS现在是值得提倡的,但不是通过谨慎地准守一个命名约定,而是在开发过程中通过独立的封装

这样也会引发一个问题:

如果大部分的css都需要是全局的,特殊的部分比较少?

引入局部作用域对我们处理CSS有重大的的连锁反应。命名规范,重用模式,潜在的样式抽离,分包等等,都会直接受到这种转变的影响

最终发展为:

在css-loader上通过一个module的标志可以支持CSS Modules

那么webpack官网上讲解的写法:

modules—启用css模块规范

关于写法:

  • 如果使用webpack中的modules的配置的话,默认就是scoped的local范围,即在本组件中使用
  • 如果需要使用全局的,可以在样式后面跟相应的全局样式,如:
1
2
3
4
:global(.title1) {
color: green;
}
.title .subTitle :global(.title1) { color: blue; }
  • 我一直在想的嵌套的lcoal写法应该怎么写,发现不能使用
1
2
3
:local(.title .subTitle){
color: blue;
}

会出现警告,这不是正确的写法,但还是会渲染出来

  • 官方给出的
1
2
3
4
:local(.className) { background: red; }
:local .className { color: green; }
:local(.className .subClass) { color: green; }
:local .className .subClass :global(.global-class-name) { color: blue; }

一开始不理解,但重要的是其原理,

1
2
3
4
5
6
7
{
loader: "css-loader",
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
}
}

局部的css 类名这些,会渲染出完整的复杂的类名,像下面这样

1
2
3
4
5
src-App__subTitle--NDKro
src: 上层文件夹名称
App: 文件名
subTitle: 类名
NDKro:哈希值

每当写一个类的时候,类似这样

1
:local(.className) { background: red; } == .className { background: red; }

默认就是 local ,webpack会为其添加前述的完整名称

对应的是:

1
<span className={ styles.title }></span>

但如果写的是

1
:global(.className) { background: red; }

渲染在页面上只是保留原有的名称,.className

对应的就是:

1
<span className="title"></span>

所以解析一下这句代码:

1
:local .className .subClass :global(.global-class-name) { color: blue; }
1
2
3
4
5
6
7
:local(.title){
color: red;
}
:global(.title){
color: bisque;
}
:local .title .subTitle .title1 { color: blue; }

上面的解析就是: 找到局部的 title, 下面的局部的subTitle, 下面的局部的title1,将相应的元素的样式设置成blue

但是如果是 上面写样式的第二种写法:

1
<span className="title"></span>

意思是直接使用的全局的样式

其实,我觉得,更合理的写法,不应该将全局和局部的样式写在一起,应该全局一个文件,局部一个文件,分别引入这样更合理一些,在局部样式种夹杂更多的全局样式,会比较混乱。

css module 里的嵌套

使用composes 下面的例子是官网上的:

1
2
3
4
:local(.continueButton) {
composes: button from 'library/button.css';
background: red;
}
1
2
3
4
:local(.nameEdit) {
composes: edit highlight from './edit.css';
background: red;
}

引入多个:

1
2
3
4
5
6
:local(.className) {
composes: edit hightlight from './edit.css';
composes: button from 'module/button.css';
composes: classFromThisModule;
background: red;
}

css Modules

在React中的实践

BEM

网易css 命名规范

使用 styled-components 加速 React 开发