你的 css 也需要模块化

uu4840 8年前
   <h2>css “局部”样式</h2>    <p>sass、less 通过 @import ,部分解决的 css 模块化的问题。</p>    <p>由于 css 是全局的,在被引入的文件和当前文件出现重名的情况下,前者样式就会被后者覆盖。</p>    <p>在引入一些公用组件,或者多人协作开发同一页面的时候,就需要考虑样式会不会被覆盖,这很麻烦。</p>    <pre>  <code class="language-css">// file A  .name {      color: red  }    // file B  @import "A.scss";  .name {      color: green  }</code></pre>    <p>css 全局样式的特点,导致 css 难以维护,所以需要一种 css “局部”样式的解决方案。</p>    <p>也就是彻底的 css 模块化, @import 进来的 css 模块,需要隐藏自己的内部作用域。</p>    <h2>CSS Modules 原理</h2>    <p>通过在每个 class 名后带一个独一无二 hash 值,这样就不有存在全局命名冲突的问题了。这样就相当于伪造了“局部”样式。</p>    <pre>  <code class="language-css">// 原始样式 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></code></pre>    <h2>webpack 与 CSS Modules</h2>    <p>webpack 自带的 css-loader 组件,自带了 CSS Modules,通过简单的配置即可使用。</p>    <pre>  <code class="language-css">{      test: /\.css$/,      loader: "css?modules&localIdentName=[name]__[local]--[hash:base64:5]"  }</code></pre>    <p>命名规范是从 BEM 扩展而来。</p>    <ul>     <li> <p>Block: 对应模块名 [name]</p> </li>     <li> <p>Element: 对应节点名 [local]</p> </li>     <li> <p>Modifier: 对应节点状态 [hash:base64:5]</p> </li>    </ul>    <p>使用 __ 和 -- 是为了区块内单词的分割节点区分开来。</p>    <p>最终 class 名为 styles__title--3zyde 。</p>    <h2>在生产环境中使用</h2>    <p>在实际生产中,结合 sass 使用会更加便利。以下是结合 sass 使用的 webpack 的配置文件。</p>    <pre>  <code class="language-css">{      test: /\.scss$/,      loader: "style!css?modules&importLoaders=1&localIdentName=[name]__[local]--[hash:base64:5]!sass?sourceMap=true&sourceMapContents=true"  }</code></pre>    <p>通常除了局部样式,还需要全局样式,比如 base.css 等基础文件。</p>    <p>将公用样式文件和组件样式文件分别放入到两个不同的目标下。如下。</p>    <pre>  <code class="language-css">.  ├── app                        │   ├── styles               # 公用样式  │   │     ├── app.scss         │   │     └── base.scss        │   │  │   └── components           # 组件            ├── Component.jsx  # 组件模板            └── Component.scss # 组件样式</code></pre>    <p>然后通过 webpack 配置,将在 app/styles 文件夹的外的(exclude) scss 文件"局部"化。</p>    <pre>  <code class="language-css">{      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"  }</code></pre>    <p>有时候,一个元素有多个 class 名,可以通过 join(" ") 或字符串模版的方式来给元素添加多个 class 名。</p>    <pre>  <code class="language-css">// 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></code></pre>    <p>如果只写一个 class 就能把样式定义好,那么最好把所有样式写在一个 class 中。</p>    <p>所以,如果我们使用了多个 class 定义样式,通常会带一些一些逻辑判断。这个时候写起来就会麻烦不少。</p>    <p>引入 classnames ,即可以解决给元素写多个 class 名的问题,也可以解决写逻辑判断的麻烦问题。</p>    <pre>  <code class="language-css">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'</code></pre>    <p>引入 CSS Modules 的样式模块,每个 class 每次都要写 styles.xxx 也是很麻烦,在《深入React技术栈》提到了 react-css-modules 的库,来减少代码的书写,感兴趣的同学可以研究下。</p>    <p>参考资料:</p>    <p>《深入React技术栈》</p>    <p><a href="/misc/goto?guid=4958965462431997440" rel="nofollow,noindex">css-modules</a></p>    <p><a href="/misc/goto?guid=4959734070170982742" rel="nofollow,noindex">CSS Modules 用法教程</a></p>    <p> </p>    <p>来自:https://segmentfault.com/a/1190000008064468</p>    <p> </p>