你的 css 也須要模塊化

css 「局部」樣式

sass、less 經過 @import ,部分解決的 css 模塊化的問題。css

因爲 css 是全局的,在被引入的文件和當前文件出現重名的狀況下,前者樣式就會被後者覆蓋。
在引入一些公用組件,或者多人協做開發同一頁面的時候,就須要考慮樣式會不會被覆蓋,這很麻煩。html

// file A
.name {
    color: red
}

// file B
@import "A.scss";
.name {
    color: green
}

css 全局樣式的特色,致使 css 難以維護,因此須要一種 css 「局部」樣式的解決方案。
也就是完全的 css 模塊化,@import 進來的 css 模塊,須要隱藏本身的內部做用域。react

CSS Modules 原理

經過在每一個 class 名後帶一個獨一無二 hash 值,這樣就不有存在全局命名衝突的問題了。這樣就至關於僞造了「局部」樣式。webpack

// 原始樣式 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,經過簡單的配置便可使用。git

{
    test: /\.css$/,
    loader: "css?modules&localIdentName=[name]__[local]--[hash:base64:5]"
}

命名規範是從 BEM 擴展而來。github

  • Block: 對應模塊名 [name]web

  • Element: 對應節點名 [local]sass

  • Modifier: 對應節點狀態 [hash:base64:5]app

使用 __ 和 -- 是爲了區塊內單詞的分割節點區分開來。
最終 class 名爲 styles__title--3zydeless

在生產環境中使用

在實際生產中,結合 sass 使用會更加便利。如下是結合 sass 使用的 webpack 的配置文件。

{
    test: /\.scss$/,
    loader: "style!css?modules&importLoaders=1&localIdentName=[name]__[local]--[hash:base64:5]!sass?sourceMap=true&sourceMapContents=true"
}

一般除了局部樣式,還須要全局樣式,好比 base.css 等基礎文件。
將公用樣式文件和組件樣式文件分別放入到兩個不一樣的目標下。以下。

.
├── 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"
}

有時候,一個元素有多個 class 名,能夠經過 join(" ") 或字符串模版的方式來給元素添加多個 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>

若是隻寫一個 class 就能把樣式定義好,那麼最好把全部樣式寫在一個 class 中。
因此,若是咱們使用了多個 class 定義樣式,一般會帶一些一些邏輯判斷。這個時候寫起來就會麻煩很多。

引入 classnames ,便可以解決給元素寫多個 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 的樣式模塊,每一個 class 每次都要寫 styles.xxx 也是很麻煩,在《深刻React技術棧》提到了 react-css-modules 的庫,來減小代碼的書寫,感興趣的同窗能夠研究下。

參考資料:
《深刻React技術棧》
css-modules
CSS Modules 用法教程

相關文章
相關標籤/搜索