CSS Modules入門及React中實踐(內附webpack4配置)

本篇文章以整理爲主,本身進行了部分修改,若有侵權,請告知

CSS Modules介紹

CSS Modules是什麼東西呢?首先,讓咱們從官方文檔入手:
GitHub – css-modules/css-modules: Documentation about css-modulescss

CSS模塊就是全部的類名都只有局部做用域的CSS文件。html

因此CSS Modules既不是官方標準,也不是瀏覽器的特性,而是在構建步驟(例如使用Webpack或Browserify)中對CSS類名選擇器限定做用域的一種方式(經過hash實現相似於命名空間的方法)。react

在使用CSS模塊時,類名是動態生成的,惟一的,並準確對應到源文件中的各個類的樣式。webpack

這也是實現樣式做用域的原理。它們被限定在特定的模板裏。例如咱們在buttons.js裏引入buttons.css文件,並使用.btn的樣式,在其餘組件裏是不會被.btn影響的,除非它也引入了buttons.css.git

可咱們是出於什麼目的把CSS和HTML文件搞得這麼零碎呢?咱們爲何要使用CSS模塊呢?github

爲何咱們須要CSS模塊化

CSS全局做用域問題,樣式衝突(污染)的問題。

  • class命名寫長一點吧,下降衝突的概率web

  • 加個父元素的選擇器,限制範圍算法

  • 從新命名個class吧,比較保險express

但是以上方案只是下降了全局衝突的機率,並不能完全解決全局衝突的問題。而且,實現方式也不夠優雅,還增長了代碼的複雜和冗餘。npm

JS CSS沒法共享變量

咱們的追求

  • 面向組件 – 處理 UI 複雜性的最佳實踐就是將 UI 分割成一個個的小組件 Locality_of_reference 。若是你正在使用一個合理的框架,JavaScript 方面就將原生支持(組件化)。舉個例子,React 就鼓勵高度組件化和分割。咱們但願有一個 CSS 架構去匹配。

  • 沙箱化(Sandboxed) – 若是一個組件的樣式會對其餘組件產生沒必要要以及意想不到的影響,那麼將 UI 分割成組件並無什麼用。就這方面而言,CSS的全局做用域會給你形成負擔。

  • 方便 – 咱們想要全部好的東西,而且不想產生更多的工做。也就是說,咱們不想由於採用這個架構而讓咱們的開發者體驗變得更糟。可能的話,咱們想開發者體驗變得更好。

CSS模塊化方案分類

CSS 模塊化的解決方案有不少,但主要有三類。

CSS 命名約定

規範化CSS的模塊化解決方案(好比BEM BEM — Block Element Modifier,OOCSS,AMCSS,SMACSS,SUITCSS)
但存在如下問題:
* JS CSS之間依然沒有打通變量和選擇器等
* 複雜的命名

CSS in JS

完全拋棄 CSS,用 JavaScript 寫 CSS 規則,並內聯樣式。 React: CSS in JS // Speaker Deck。Radium,react-style 屬於這一類。但存在如下問題:
* 沒法使用僞類,媒體查詢等
* 樣式代碼也會出現大量重複。
* 不能利用成熟的 CSS 預處理器(或後處理器)

關注點分離:是將計算機程序分紅不一樣部分的設計原則,所以每一個部分都須要解決一個獨立的問題。HTML主要用於組織網頁內容,CSS用於定義內容呈現風格,JS定義內容如何與用戶交互和行爲。

維基百科:https://en.wikipedia.org/wiki/Separation_of_concerns#HTML.2C_CSS.2C_JavaScript

使用JS 來管理樣式模塊

使用JS編譯原生的CSS文件,使其具有模塊化的能力,表明是 CSS Modules GitHub – css-modules/css-modules: Documentation about css-modules 。

CSS Modules 能最大化地結合現有 CSS 生態(預處理器/後處理器等)和 JS 模塊化能力,幾乎零學習成本。只要你使用 Webpack,能夠在任何項目中使用。是筆者認爲目前最好的 CSS 模塊化解決方案。

CSS Modules 使用教程

webpack配置(版本爲webpack4)

手動引用解決

在 className 處直接使用 css 中 class 名便可。

注意到 table--table-32osj 是 CSS Modules 按照 localIdentName 自動生成的 class 名。其中的 32osj  是按照給定算法生成的序列碼。通過這樣混淆處理後,class 名基本就是惟一的,大大下降了項目中樣式覆蓋的概率。同時在生產環境下修改規則,生成更短的 class 名,能夠提升 CSS 的壓縮率。

CSS Modules 實現瞭如下幾點:
* 全部樣式都是局部做用域的,解決了全局污染問題
* class 名生成規則配置靈活,能夠此來壓縮 class 名
* 只需引用組件的 JS 就能搞定組件全部的 JS 和 CSS
* 依然是 CSS,幾乎 0 學習成本

babel-plugin-react-css-modules

babel-plugin-react-css-modules 能夠實現使用styleName屬性自動加載CSS模塊。咱們經過該babel插件來進行語法樹解析並最終生成className。

以這種方式使用CSS模塊有幾個缺點:

  • 您必須使用camelCase CSS類名稱。

  • 每當構造一個className時,你必須使用styles對象。

  • 混合CSS模塊和全局CSS類很麻煩。

  • 對未定義的CSS模塊的引用解決爲未定義而沒有警告。

  • 您沒必要強迫使用camelCase命名約定。

  • 每次使用CSS模塊時,不須要引用樣式對象。

  • 全局CSS和CSS模塊之間有明顯的區別,例如

工做原理

那麼該babel插件是怎麼工做的呢?讓咱們從官方文檔入手:

GitHub – gajus/babel-plugin-react-css-modules: Transforms styleName to className using compile time CSS module resolution.

翻譯以下:
1. 構建每一個文件的全部樣式表導入的索引(導入具備.css或.scss擴展名的文件)。
2. 使用postcss 解析匹配到的css文件
3. 遍歷全部 JSX 元素聲明
4. 把styleName 屬性解析成匿名和命名的局部css模塊引用
5. 查找與CSS模塊引用相匹配的CSS類名稱:
* 若是styleName的值是一個字符串字面值,生成一個字符串字面值。
* 若是是JSXExpressionContainer,在運行時使用helper函數來構建若是styleName的值是一個 jSXExpressionContainer, 使用輔助函數([getClassName]在運行時構造className值。
6. 從元素上移除styleName屬性。
7. 將生成的className添加到現有的className值中(若是不存在則建立className屬性)。

使用實例

在成熟的項目中,通常都會用到CSS預處理器或者後處理器。

這裏以使用了scss預處理器爲例子,咱們來看下如何使用。

代碼塊
Plain Text
 
 
npm install -save-dev postcss-scss postcss-nested babel-plugin-react-css-modules

 

 

最後

CSS Modules 很好的解決了 CSS 目前面臨的模塊化難題。支持與 CSS處理器搭配使用,能充分利用現有技術積累。若是你的產品中正好遇到相似問題,很是值得一試。

相關文章
相關標籤/搜索