什么是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
點贊👍+關注我吧~
我只想成為更好的自己
