CSS Module用法总结
什么是CSS Modules?
官方解释是:GitHub - css-modules/css-modules: Documentation about css-modules
可以理解为:所有的类名和动画名称默认都有各自的作用域的css文件。
通俗点来说是,每个class类是独立的可以被单独的按照某种规则编译为独一无二的域名,或者你也可以理解为,每个class都有自己的scope。
css作用域
目前css作用域有三种方案
1.css modules
2.css in js
3.BEM +scope
其中1、3的区别如下
- 只要是靠人去保证代码质量总是不靠谱的,人的状态有起伏,但是机器没有,因此推荐用机器去解决这些问题。这个是BEM+scope比较欠缺的
- 需要注意css穿透,如果要改一些第三方的东西(当然写起来也比较简单),具体的可以了解下样式穿透
- BEM写起来很繁琐,而且是靠人去解决重名的问题。
那么cssModule解决了什么问题?
1.变量全局污染问题
css scope也能解决这个问题,但是解决问题的思路不一样,scope解决全局样式污染的问题的解决办法是通过,scope来限制子作用域对父作用域(也可以是全局作用域)的污染
css module解决办法是通过
:local(.text){ color:red }
:local函数来解决这个问题
:global(.class){ }
:global能在子页面内写全局变量(我们在修改第三方库的时候通常会使用这个函数)
2.对比BEM,BEM相对繁琐,而CSS Modulex相对灵活
胜出原因:
1.BEM的解决办法是通过人来保证css的唯一性,CSS Module是通过webpack的打包机制类解决这个问题。
打包代码之前
<h1 class="test"> An example heading </h1>
打包代码之后
<h1 class="_styles__test_309571057"> An example heading </h1>
2.灵活,并且不同css文件内即使相同的class也不会互相影响
举个栗子
import real from './real.css' import fake from './fake.css' element.innerHTML = `<div class="${buttons.red} ${padding.large}">`;
本质上,这种引入两个文件夹的写法是完全可以的,但是有些时候这种形式的代码复用是很实用的,还有一个不经常用的写法
.element { composes: dark-red from "./colors.css"; font-size: 30px; line-height: 1.2; }
借助CSS Module的compose,来解决这个事情。
那么怎么使用CSS Module?
看了阮一峰大大的CSS Module教程,总结如下:
使项目支持CSS Module
安装对应的包
TypeScript
,所以可以用typings-for-css-modules-loader这个包,这个包也可以替代css-loader
的功能,此外这个包还能根据.scss
文件里面的类名自动生成对应的.d.ts
文件:npm install -D typings-for-css-modules-loader
配置webpack
这个配置接非常简单了,因为要用typings-for-css-modules-loader
替代css-loader
的功能,所以直接替换即可,将前面sass的配置修改为如下:
配置后在页面中引入,引入可能会提示找不到该模块,出现这个问题的原因是:
因为.scss文件中并没有类似export这样的关键词用于导出一个模块,所以也就导致报错找不到模块,这个问题需要通过ts的模块声明解决。(declare module)
解决声明模块问题
在根目录新建一个typings文件夹,存放.scss的模块声明,以及后续需要用到的全局interface等,结构和声明内容如下:
接下来就可以愉快的写CSS module了
CSS Module 全局作用域
CSS Modules 允许使用:global(.className)
的语法,声明一个全局规则。凡是这样声明的class
,都不会被编译成哈希字符串。
.title { color: red; } :global(.title) { color: green; }
App.js
使用普通的class
的写法,就会引用全局class
。
import React from 'react'; import styles from './App.css'; export default () => { return ( <h1 className="title"> Hello World </h1> ); };
CSS Modules 还提供一种显式的局部作用域语法:local(.className)
,等同于.className
,所以上面的App.css
也可以写成下面这样。
:local(.title) { color: red; } :global(.title) { color: green; }
定制哈希类名
css-loader
默认的哈希算法是[hash:base64]
,这会将.title
编译成._3zyde4l1yATCOkgn-DBWEL
这样的字符串。
webpack.config.js
里面可以定制哈希字符串的格式。(此处引用typings-for-css-modules-loader没有尝试过定制哈希,你们可以用css-loader的方式尝试一下)
module: { loaders: [ // ... { test: /\.css$/, loader: "style-loader!css-loader?modules&localIdentName=[path][name]---[local]---[hash:base64:5]" }, ] }
然后.tille 就变成了 (路径名)_title__2DtM1
Class组合
在CSS Modules中,一个选择器可以继承另一个选择器的规则,这称为组合(composition)
.className { background-color: blue; } .title { composes: className; color: red; }
输入变量
CSS Modules 支持使用变量,不过需要安装 PostCSS 和 postcss-modules-values。
npm install --save postcss-loader postcss-modules-values
把postcss-loader
加入webpack.config.js
。
const values = require('postcss-modules-values'); module.exports = { entry: __dirname + '/index.js', output: { publicPath: '/', filename: './bundle.js' }, module: { loaders: [ { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel', query: { presets: ['es2015', 'stage-0', 'react'] } }, { test: /\.css$/, loader: "style-loader!css-loader?modules!postcss-loader" }, ] }, postcss: [ values ] };
接着,在colors.css
里面定义变量。
@value blue: #0c77f8; @value red: #ff0000; @value green: #aaf200;
App.css
可以引用这些变量。
@value colors: "./colors.css"; @value blue, red, green from colors; .title { color: red; background-color: blue; }
参考:https://zhuanlan.zhihu.com/p/99748333
参考:http://www.ruanyifeng.com/blog/2016/06/css_modules.html
点赞👍+关注我吧~
我只想成为更好的自己