css “局部”樣式
sass、less 通過 @import
,部分解決的 css 模塊化的問題。
由于 css 是全局的,在被引入的文件和當(dāng)前文件出現(xiàn)重名的情況下,前者樣式就會(huì)被后者覆蓋。
在引入一些公用組件,或者多人協(xié)作開發(fā)同一頁面的時(shí)候,就需要考慮樣式會(huì)不會(huì)被覆蓋,這很麻煩。
// file A .name { color: red } // file B @import "A.scss"; .name { color: green }
css 全局樣式的特點(diǎn),導(dǎo)致 css 難以維護(hù),所以需要一種 css “局部”樣式的解決方案。
也就是徹底的 css 模塊化,@import
進(jìn)來的 css 模塊,需要隱藏自己的內(nèi)部作用域。
CSS Modules 原理
通過在每個(gè) class 名后帶一個(gè)獨(dú)一無二 hash 值,這樣就不有存在全局命名沖突的問題了。這樣就相當(dāng)于偽造了“局部”樣式。
// 原始樣式 styles.css .title { color: red; } // 原始模板 demo.html import styles from 'styles.css'; <h1 class={styles.title}> Hello World </h1> // 編譯后的 styles.css .title_3zyde { color: red; } // 編譯后的 demo.html <h1 class="title_3zyde"> Hello World </h1>
webpack 與 CSS Modules
webpack 自帶的 css-loader
組件,自帶了 CSS Modules,通過簡(jiǎn)單的配置即可使用。
{ test: /.css$/, loader: "css?modules&localIdentName=[name]__[local]--[hash:base64:5]" }
命名規(guī)范是從 BEM 擴(kuò)展而來。
-
Block: 對(duì)應(yīng)模塊名
[name]
-
Element: 對(duì)應(yīng)節(jié)點(diǎn)名
[local]
-
Modifier: 對(duì)應(yīng)節(jié)點(diǎn)狀態(tài)
[hash:base64:5]
使用 __ 和 — 是為了區(qū)塊內(nèi)單詞的分割節(jié)點(diǎn)區(qū)分開來。
最終 class 名為 styles__title--3zyde
。
在生產(chǎn)環(huán)境中使用
在實(shí)際生產(chǎn)中,結(jié)合 sass 使用會(huì)更加便利。以下是結(jié)合 sass 使用的 webpack 的配置文件。
{ test: /.scss$/, loader: "style!css?modules&importLoaders=1&localIdentName=[name]__[local]--[hash:base64:5]!sass?sourceMap=true&sourceMapContents=true" }
通常除了局部樣式,還需要全局樣式,比如 base.css 等基礎(chǔ)文件。
將公用樣式文件和組件樣式文件分別放入到兩個(gè)不同的目標(biāo)下。如下。
. ├── app │ ├── styles # 公用樣式 │ │ ├── app.scss │ │ └── base.scss │ │ │ └── components # 組件 ├── Component.jsx # 組件模板 └── Component.scss # 組件樣式
然后通過 webpack 配置,將在 app/styles
文件夾的外的(exclude) scss 文件"局部"化。
{ test: /.scss$/, exclude: path.resolve(__dirname, 'app/styles'), loader: "style!css?modules&importLoaders=1&localIdentName=[name]__[local]--[hash:base64:5]!sass?sourceMap=true&sourceMapContents=true" }, { test: /.scss$/, include: path.resolve(__dirname, 'app/styles'), loader: "style!css?sass?sourceMap=true&sourceMapContents=true" }
有時(shí)候,一個(gè)元素有多個(gè) class 名,可以通過 join(" ")
或字符串模版的方式來給元素添加多個(gè) class 名。
// join-react.jsx <h1 className={[styles.title,styles.bold].join(" ")}> Hello World </h1> // stringTemp-react.jsx <h1 className={`${styles.title} ${styles.bold}`}> Hello World </h1>
如果只寫一個(gè) class 就能把樣式定義好,那么最好把所有樣式寫在一個(gè) class 中。
所以,如果我們使用了多個(gè) class 定義樣式,通常會(huì)帶一些一些邏輯判斷。這個(gè)時(shí)候?qū)懫饋砭蜁?huì)麻煩不少。
引入 classnames ,即可以解決給元素寫多個(gè) class 名的問題,也可以解決寫邏輯判斷的麻煩問題。
classNames('foo', 'bar'); // => 'foo bar' classNames('foo', { bar: true }); // => 'foo bar' classNames({ 'foo-bar': true }); // => 'foo-bar' classNames({ 'foo-bar': false }); // => '' classNames({ foo: true }, { bar: true }); // => 'foo bar' classNames({ foo: true, bar: true }); // => 'foo bar' // lots of arguments of various types classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux' // other falsy values are just ignored classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
引入 CSS Modules 的樣式模塊,每個(gè) class 每次都要寫 styles.xxx
也是很麻煩,在《深入React技術(shù)?!诽岬搅?react-css-modules
的庫,來減少代碼的書寫,感興趣的同學(xué)可以研究下。
推薦學(xué)習(xí):《css視頻教程》