前端發展愈來愈快,這應該是每一個前端開發者的切身感覺,可是CSS 是前端領域中進化最慢的一塊。ES678快速普及前端工程發愈發成熟,CSS 被被遠遠甩在了後面,JS語言模塊已經標準化,CSS仍是在不斷探索,同時這也是一個急需解決的問題。css
要是你之前還從未據說過CSS Modules,那麼這篇就是專門寫給你的。若是你瞭解過它,你就不必再看了,由於他真的很簡單(很強大)。html
咱們都知道,CSS入門簡單,深刻就比較難,樣式簡單維護難。CSS痛點也不少前端
一、CSS 的規則是全局的,任何一個組件的樣式規則,都對整個頁面有效。相信寫css的人都會遇到樣式衝突(污染)的問題。webpack
二、爲了解決全局污染的問題,那就把class命名寫長一點吧、加一層父級選擇器、下降衝突的概率,那麼CSS命名混亂了git
三、組件依賴管理不完全,組件應該相互獨立,引入一個組件時,應該只引入它所須要的 CSS 樣式。github
四、代碼難以複用,出現了sass less 之類的工具web
前端發展是飛速的每天有新輪子。天然CSS 模塊化的解決方案有不少,但主要有三類:算法
規範化CSS的解決方案如:BEM、OOCSS、AMCSS、SMACSS編程
完全拋棄 CSS,用 JavaScript 寫 CSS 規則,styled-components 就是其中表明。sass
使用JS編譯原生的CSS文件,使其具有模塊化的能力,表明是 CSS Modules。
可是這些模塊化方案都是各有優缺點,如命名約定:命名複雜、CSS in JS:缺少擴展、 CSS Modules固然也有一些缺點(你得先學會它再去談優劣)。在衆多解決方案中,沒有絕對的優劣。仍是要結合本身的場景來決定。
CSS Modules不是將CSS改造的具備編程能力,而是加入了局部做用域、依賴管理,這偏偏解決了最大的痛點。能夠有效避免全局污染和樣式衝突,能最大化地結合現有 CSS 生態和 JS 模塊化能力。
CSS Modules 很容易學。webpack 自帶的 css-loader
組件,自帶了 CSS Modules,經過簡單的配置便可使用。
// webpack.config.js const path = require('path') module.exports = { entry: __dirname + '/src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', { loader: 'css-loader', options: { modules: true, } } ] } ] } } // 也可使用下面這種寫法 // loader: "style-loader!css-loader?modules"
如今咱們來寫個Button組件
/* Button.css */ .primary { background-color: #1aad19; color: #fff; border: none; border-radius: 5px; }
// Button.js import styles from './Button.css'; console.log(styles); // -> {primary: "yTXmm0isaXExoYiZUvKxH"} const Button = document.createElement('div') Button.innerHTML = `<button class=${styles.primary}>Submit</button>` export default Button // index.js import Button from './components/Button' const app = document.getElementById('root') app.appendChild(Button)
生成HTML爲
<div id="root"> <div> <button class="yTXmm0isaXExoYiZUvKxH">Submit</button> </div> </div> <!-- yTXmm0isaXExoYiZUvKxH爲CSS Modules自動生成的class類名 -->
CSS Modules 對 CSS 中的 class 名都作了處理,使用對象來保存原 class 和混淆後 class 的對應關係。CSS Modules自動生成的class類名基本就是惟一的,大大下降了項目中樣式覆蓋衝突的概率。
GitHub 示例庫 https://github.com/liuxing/css-modules-demo 經過commit 記錄來查看
css-loader
默認的哈希算法是[hash:base64]
,從前面咱們能夠發現.primary
被編譯成了 yTXmm0isaXExoYiZUvKxH 這樣的字符串。這名字也沒風格了別擔憂,css-loader 爲咱們提供了localIdentName
參數指定生成的名字格式。localIdentName
的默認值是[hash:base64]
。
... { loader: 'css-loader', options: { modules: true, localIdentName: '[name]__[local]--[hash:base64:5]' } } // 或者 loader: 'style-loader!css-loader?modules&localIdentName=[name]__[local]--[hash:base64:5]' ...
BEM代碼規範再也不是必須的 熟悉BEM的同窗可能發現了上面的命名和BEM有些神似, 雖然它的命名有點奇特,可是 BEM 被很是多的大型項目和團隊採用,這是一種很好的實踐。固然了隨便怎麼寫均可以結合本身的場景來決定,在CSS module中再也不須要遵照BEM規範。
經過前面的例子能夠感覺到CSS module處理CSS的方式。如今咱們從頭來講做用域。
CSS不少問題都是由於全局做用域引發的,怎麼樣才能產生局部做用域?經過前面CSS module的例子咱們發現它思路很簡單就是生成惟一的class類名。CSS module將class轉換成對應的全局惟一hash值來造成局部做用域。使用了 CSS Modules 後,就至關於給每一個 class 名外加了一個 :local
這是默認的,也能夠顯式使用
固然,若是你想切換到全局模式,CSS Modules 容許使用:global(.className)
的語法,聲明一個全局規則。凡是這樣聲明的class
,都不會被編譯成哈希字符串。
/* Button.css */ :global(.btn) { color: #fff; border: none; border-radius: 5px; } .primary { background-color: #1aad19; } /* 與上面不加`:local`等價 顯式的局部做用域語法 */ :local(.warn) { background-color: #e64340 }
經過 GitHub 示例庫 https://github.com/liuxing/css-modules-demo 的commit 記錄來查看
對於樣式複用,CSS Modules 提供了 composes
組合 的方式來處理。一個選擇器能夠繼承另外一個選擇器的規則
/* Button.css */ .btn { /* 全部通用的樣式 */ color: #fff; border: none; border-radius: 5px; box-sizing: border-box; } .primary { composes: btn; background-color: #1aad19; }
Button.js
import styles from './Button.css'; console.log(styles); const Button = document.createElement('div') Button.innerHTML = `<button class="${styles.primary}">Submit</button>` export default Button
生成的 HTML 變爲
<div id="root"> <div> <button class="Button__primary--yTXmm Button__btn--nx67B">Submit</button> </div> </div>
咱們發如今 .primary
中 composes 了 .btn
,編譯後 .primary
會變成兩個 class。
composes 還能夠也能夠繼承組合其餘CSS文件裏面的規則
/* author.css */ .shadow { box-shadow: 0 0 20px rgba(0, 0, 0, .2) }
Button.css
··· .primary { composes: btn; composes: shadow from './author.css'; background-color: #1aad19; } ···
這是個很強大方便的功能,CSS Modules團隊成員認爲composes
是CSS Modules裏最強大的功能:
For me, the most powerful idea in CSS Modules is composition, where you can deconstruct your visual inventory into atomic classes, and assemble them at a module level, without duplicating markup or hindering performance.
爲了追求簡單可控,做者建議遵循以下原則:
composes
組合來實現複用可是建議只是建議,CSS Modules 並不強制你必定要這麼作。怎麼舒服怎麼來
CSS Modules 很好的解決了 CSS 目前面臨的一些痛點以及模塊化難題,同時也支持與 Sass/Less/PostCSS 等搭配使用。
不管是經過遵循的命名標準化的規範,仍是使用本文介紹的CSS Modules,目的都是同樣:可維護的css代碼。具體使用不是有仍是要結合本身的場景來決定。適合的纔是最好的
你們能夠關注個人公衆號,一塊兒玩耍。有技術乾貨也有扯淡亂談,關注回覆[888]領取福利
左手代碼右手磚,拋磚引玉