摘要:樣式變多后,命名將更加混亂。缺點是不能利用成熟的預處理器或后處理器,和偽類處理起來復雜。經過這樣混淆處理后,名基本就是唯一的,大大降低了項目中樣式覆蓋的幾率。就只能使用預處理器自己的語法來做樣式復用了。
一 前言
CSS 是前端領域中進化最慢的一塊。由于 ES2015/2016 的快速普及和 Babel/Webpack 等工具的迅猛發展,CSS 被遠遠甩在了后面,逐漸成為大型項目工程化的痛點。也變成了前端走向徹底模塊化前必須解決的難題。
模塊化解決了JS作用域的問題,但是CSS還是會存在樣式覆蓋的問題,因為最后打包最終會生成一份文件而不是開發時候的那樣分模塊分作用域。
所以,我們今天討論的是如何在模塊化的工程下放心的寫CSS樣式而不擔心樣式覆蓋,推薦的方案就是CSS Module。
二 正文1.CSS 模塊化遇到了哪些問題
CSS 模塊化重要的是要解決好兩個問題:CSS 樣式的導入和導出。
樣式導入:靈活按需導入以便復用代碼;
樣式導出:導出時要能夠隱藏內部作用域,以免造成全局污染。
Sass/Less/PostCSS 等前仆后繼試圖解決 CSS 編程能力弱的問題,結果它們做的也確實優秀,但這并沒有解決模塊化最重要的問題。Facebook 工程師 Vjeux 首先拋出了 React 開發中遇到的一系列 CSS 相關問題。總結如下:
全局污染
CSS 使用全局選擇器機制來設置樣式,優點是方便重寫樣式。缺點是所有的樣式都是全局生效,樣式可能被錯誤覆蓋,因此產生了非常丑陋的 !important,甚至 inline !important 和復雜的選擇器權重計數表,提高犯錯概率和使用成本。 Web Components 標準中的 Shadow DOM 能徹底解決這個問題,但它的做法有點極端,樣式徹底局部化,造成外部無法重寫樣式,損失了靈活性。
命名混亂
由于全局污染的問題,多人協同開發時為了避免樣式沖突,選擇器越來越復雜,容易形成不同的命名風格,很難統一。樣式變多后,命名將更加混亂。
依賴管理不徹底
組件應該相互獨立,引入一個組件時,應該只引入它所需要的 CSS 樣式。但現在的做法是除了要引入 JS,還要再引入它的 CSS,而且 Saas/Less 很難實現對每個組件都編譯出多帶帶的 CSS,引入所有模塊的 CSS 又造成浪費。JS 的模塊化已經非常成熟,如果能讓 JS 來管理 CSS 依賴是很好的解決辦法。 Webpack 的 css-loader 提供了這種能力。
無法共享變量
復雜組件要使用 JS 和 CSS 來共同處理樣式,就會造成有些變量在 JS 和 CSS 中冗余,Sass/PostCSS/CSS 等都不提供跨 JS 和 CSS 共享變量這種能力。
代碼壓縮不徹底
由于移動端網絡的不確定性,現在對 CSS 壓縮已經到了{{BANNED}}的程度。很多壓縮工具為了節省一個字節會把 "16px" 轉成 "1pc"。但對非常長的 class 名卻無能為力,力沒有用到刀刃上。
上面的問題如果只憑 CSS 自身是無法解決的,如果是通過 JS 來管理 CSS 就很好解決,因此 Vjuex 給出的解決方案是完全的 CSS in JS,但這相當于完全拋棄 CSS,在 JS 中以 Object 語法來寫 CSS,估計剛看到的小伙伴都受驚了。直到出現了 CSS Modules。
2.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 模塊化能力,API 簡潔到幾乎零學習成本。 發布時依舊編譯出多帶帶的 JS 和 CSS。它并不依賴于 React,只要你使用 Webpack,可以在 Vue/Angular/jQuery 中使用。
3.為什么是CSS Module
CSS Modules 能最大化地結合現有 CSS 生態和 JS 模塊化能力,API 簡潔到幾乎零學習成本。
發布時依舊編譯出多帶帶的 JS 和 CSS。它并不依賴于 React,只要你使用 Webpack,可以在 Vue/Angular/jQuery 中使用。
4.使用CSS Module
CSS Modules 內部通過 ICSS 來解決樣式導入和導出這兩個問題。分別對應 :import 和 :export 兩個新增的偽類。
:import("path/to/dep.css") { localAlias: keyFromDep; /* ... */ } :export { exportedKey: exportedValue; /* ... */ }
但直接使用這兩個關鍵字編程太麻煩,實際項目中很少會直接使用它們,我們需要的是用 JS 來管理 CSS 的能力。結合 Webpack 的 css-loader 后,就可以在 CSS 中定義樣式,在 JS 中導入。
啟用 CSS Modules
// webpack.config.js css?modules&localIdentName=[name]__[local]-[hash:base64:5]
加上 modules 即為啟用,localIdentName 是設置生成樣式的命名規則。
也可以這樣設置:
test: /.less$/, use: [ "style-loader", { loader: "css-loader", options: { modules: true, localIdentName: "[name]__[local]-[hash:base64:5]", }, }, ], },
樣式文件Button.css:
.normal { /* normal 相關的所有樣式 */ } .disabled { /* disabled 相關的所有樣式 */ } /* components/Button.js */ import styles from "./Button.css"; console.log(styles); buttonElem.outerHTML = ``
生成的 HTML 是
注意到 button--normal-abc53 是 CSS Modules 按照 localIdentName 自動生成的 class 名。其中的 abc53 是按照給定算法生成的序列碼。經過這樣混淆處理后,class 名基本就是唯一的,大大降低了項目中樣式覆蓋的幾率。同時在生產環境下修改規則,生成更短的class名,可以提高CSS的壓縮率。
上例中 console 打印的結果是:
Object { normal: "button--normal-abc53", disabled: "button--disabled-def884", }
CSS Modules 對 CSS 中的 class 名都做了處理,使用對象來保存原 class 和混淆后 class 的對應關系。
通過這些簡單的處理,CSS Modules 實現了以下幾點:
所有樣式都是 local 的,解決了命名沖突和全局污染問題
class 名生成規則配置靈活,可以此來壓縮 class 名
只需引用組件的 JS 就能搞定組件所有的 JS 和 CSS
依然是 CSS,幾乎 0 學習成本
樣式默認局部
使用了 CSS Modules 后,就相當于給每個 class 名外加加了一個 :local,以此來實現樣式的局部化,如果你想切換到全局模式,使用對應的 :global。
.normal { color: green; } /* 以上與下面等價 */ :local(.normal) { color: green; } /* 定義全局樣式 */ :global(.btn) { color: red; } /* 定義多個全局樣式 */ :global { .link { color: green; } .box { color: yellow; } }
Compose 來組合樣式
對于樣式復用,CSS Modules 只提供了唯一的方式來處理:composes 組合
/* components/Button.css */ .base { /* 所有通用的樣式 */ } .normal { composes: base; /* normal 其它樣式 */ } .disabled { composes: base; /* disabled 其它樣式 */ } import styles from "./Button.css"; buttonElem.outerHTML = ``
生成的 HTML 變為
由于在 .normal 中 composes 了 .base,編譯后會 normal 會變成兩個 class。
composes 還可以組合外部文件中的樣式。
/* settings.css */ .primary-color { color: #f40; } /* components/Button.css */ .base { /* 所有通用的樣式 */ } .primary { composes: base; composes: primary-color from "./settings.css"; /* primary 其它樣式 */ }
對于大多數項目,有了 composes 后已經不再需要 Sass/Less/PostCSS。但如果你想用的話,由于 composes 不是標準的 CSS 語法,編譯時會報錯。就只能使用預處理器自己的語法來做樣式復用了。
class 命名技巧
CSS Modules 的命名規范是從 BEM 擴展而來。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/113527.html
摘要:官方文檔可以直接在能跑起來的項目中使用。所以在使用的父組件中使用的子組件也要開啟。能正常編譯,而則會編譯的不符合預期,所以平時養成良好的參數書寫順序也很重要。總結總結綜上所述,前期進行不麻煩的配置,實現的效果比更優,這里推薦使用。scoped css 官方文檔 scoped css可以直接在能跑起來的vue項目中使用。 使用方法: h1 { color: #f00; } 使用scop...
摘要:網上看了很多配置,最后才發現后就不用就可以使用特性,那么仿照的配置即可的使用將文件名為配置暴露配置文件安裝依賴修改文件配置,一共修改三處第一處增加定義變量第二處仿照配置第三處修改函數內部,增加圖片描述測試是否安裝成功 網上看了很多配置,最后才發現create-react-app2.0后就不用eject就可以使用css module特性,那么less仿照css的配置即可 1.css mo...
摘要:網上看了很多配置,最后才發現后就不用就可以使用特性,那么仿照的配置即可的使用將文件名為配置暴露配置文件安裝依賴修改文件配置,一共修改三處第一處增加定義變量第二處仿照配置第三處修改函數內部,增加圖片描述測試是否安裝成功 網上看了很多配置,最后才發現create-react-app2.0后就不用eject就可以使用css module特性,那么less仿照css的配置即可 1.css mo...
摘要:前言前言本文講述開啟模塊功能之后,如何與引用的包中樣式文件不產生沖突。在不做特殊處理的前提下,樣式文件將會被轉譯成。前言 本文講述css-loader開啟css模塊功能之后,如何與引用的npm包中樣式文件不產生沖突。 比如antd-mobilenpm包的引入。在不做特殊處理的前提下,樣式文件將會被轉譯成css module。 一、產生問題的原因 { test: /.css$/, ...
摘要:支持轉義轉義需要的依賴,支持裝飾器。在中增加的配置數組中。壓縮文件安裝依賴在中的中增加配置打包前先清空輸出目錄在中增加的配置至此,配置已經基本能滿足需求。 webpack 核心概念: Entry: 入口 Module:模塊,webpack中一切皆是模塊 Chunk:代碼庫,一個chunk由十多個模塊組合而成,用于代碼合并與分割 Loader:模塊轉換器,用于把模塊原內容按照需求轉換成...
摘要:一看就懂之基礎配置一簡介本質上,是一個現代應用程序的靜態模塊打包器。屬性表示的是的上下文目錄,配置入口文件的時候,如果入口文件使用的是相對路徑,那么就是相對于所在的目錄。通常用于指定以何種方式導出庫,通常用于指定接收庫的名稱。 一看就懂之webpack基礎配置 一、webpack 簡介 本質上,webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module b...
閱讀 1571·2021-10-14 09:42
閱讀 3814·2021-09-07 09:59
閱讀 1291·2019-08-30 15:55
閱讀 572·2019-08-30 11:17
閱讀 3337·2019-08-29 16:06
閱讀 500·2019-08-29 14:06
閱讀 3121·2019-08-28 18:14
閱讀 3641·2019-08-26 13:55