CSS Modules使用詳解
- 2019 年 12 月 4 日
- 筆記
CSS Modules
CSS 模組化
不管是用jquery還是react開發,都會遇到的一系列 CSS 的問題:
- 全局污染
- 命名混亂
- 依賴引入複雜
- 無法共享變數
- 程式碼冗餘
通過 JS 來管理 CSS 就很好解決上述列舉的問題。CSS 模組化的解決方案有很多,但主要有兩類。
一類是徹底拋棄 CSS,使用 JS 或 JSON 來寫樣式。Radium, jsxstyle ,react-style 屬於這一類。優點是能給 CSS 提供 JS 同樣強大的模組化能力;缺點是不能利用成熟的 CSS 預處理器(或後處理器) Sass/Less/PostCSS, :hover 和 :active 偽類處理起來複雜。
另一類是依舊使用 CSS,但使用 JS 來管理樣式依賴,代表是CSS Modules。CSS Modules 能最大化地結合現有 CSS 生態和 JS 模組化能力。發布時依舊編譯出單獨的 JS 和 CSS。它並不依賴於 React,只要你使用 Webpack,可以在 Vue/Angular/jQuery 中使用。
啟用 CSS Modules
// webpack.config.js css?modules&localIdentName=[name]__[local]-[hash:base64:5]
加上 modules 即為啟用, localIdentName 是設置生成樣式的命名規則,[name]表示標籤名,[local]表示類名,[hash:base64:5]是按照給定演算法生成的序列碼。
/* components/test.css */ .active { color: red; } .disabled { color: gray; } /* components/test.js */ import styles from './test.css'; console.log(styles); elem.outerHTML = `<h1 class=${styles.active}>CSS Modules</h1>`
生成的 HTML 是
<h1 class="h1--active-abc53"> Processing... </h1>
它將根據 styleName 的值在關聯的 style 對象中查找對應的 CSS Modules,並為 ReactElement className 屬性值添加相匹配的獨一無二的 CSS 類名。
上例中 styles的consolelog 列印的結果是:
Object { active: 'h1--active-abc53', disabled: 'h1--disabled-def84', }
CSS Modules 對 CSS 中的 class 名都做了處理,使用對象來保存原 class 和訂製處理後的 class 的對應關係。經過這樣類名訂製處理後,class 名基本就是唯一的,大大降低了項目中樣式覆蓋的幾率。同時可以生成更短的 class 名,減少程式碼量。
CSS Modules 使用
局部變數和全局變數
:local
: 做localIdentName
規則處理:global
: 樣式編譯後不變
如果書寫時不加,默認處理為:local
。
.normal { color: green; } :local(.normal) { color: green; } /* 上面兩個等價,默認給每個 class 名外加加了一個 `:local` */ /* 全局樣式 */ :global { .link { color: green; } .box { color: yellow; } }
唯一哈希類名
開啟CSS Modules時定義的規則localIdentName=[name]__[local]-[hash:base64:5]
會控制對class名的處理, [hash:base64:5]定義的hash計算能保證類名的唯一性。
Compose 組合Class
很多時候我們都需要樣式復用,在 CSS Modules 中,一個選擇器可以繼承另一個選擇器的規則,這稱為composes
組合。
/* components/test.css */ .bg { background-color: blue; } .title { composes: bg; color: white; } /* components/test.js */ import styles from './test.css'; elem.outerHTML = `<h1 class=${styles.title}>CSS Modules</h1>`
生成的 HTML 為
<h1 class="h1--bg-fec53 h1--title-Ijf8"> Processing... </h1>
CSS和JS變數共享
:export 關鍵字可以把 CSS 中的 變數輸出到 JS 中:
/* index.scss */ $primary-color: #f40; :export { primaryColor: $primary-color; } /* app.js */ import style from 'index.scss'; // 會輸出 #F40 console.log(style.primaryColor);
CSS Modules使用特點
- 不使用選擇器,只使用 class 名來定義樣式
- 不層疊多個 class,只使用一個 class 把所有樣式定義好
- 不嵌套class
- 所有樣式通過 composes 組合來實現復用
舊項目的兼容
- 如果對一個元素使用多個 class,樣式照樣生效。
- 如何在一個 style 文件中使用同名 class ,編譯後仍是同名的。
- 如果在 style 文件中使用了 id 選擇器,偽類,標籤選擇器,所有這些選擇器將不被轉換,原封不動的出現在編譯後的 css 中。即 CSS Modules 只會轉換 class 名相關樣式。
- 當類名經過編譯生成新的隨機類名後,可以解決命名衝突,但因為無法預知最終 class 名,不能通過一般選擇器覆蓋。現在一般給出的項目中的實踐是可以給組件關鍵節點加上 data-role 屬性,然後通過屬性選擇器來覆蓋樣式。
- 前端項目不可避免會引入 normalize.css 或其它一類全局 css 文件。使用 Webpack 可以讓全局樣式和 CSS Modules 的局部樣式和諧共存。
module: { loaders: [{ test: /.jsx?$/, loader: 'babel' }, { test: /.scss$/, exclude: path.resolve(__dirname, 'src/styles'), loader: 'style!css?modules&localIdentName=[name]__[local]!sass?sourceMap=true' }, { test: /.scss$/, include: path.resolve(__dirname, 'src/styles'), loader: 'style!css!sass?sourceMap=true' }] }