CSS Modules使用详解

gzsinx 8年前
   <h2>CSS Modules</h2>    <h3>CSS 模块化</h3>    <p>不管是用jquery还是react开发,都会遇到的一系列 CSS 的问题:</p>    <ol>     <li>全局污染</li>     <li>命名混乱</li>     <li>依赖引入复杂</li>     <li>无法共享变量</li>     <li>代码冗余</li>    </ol>    <p>通过 JS 来管理 CSS 就很好解决上述列举的问题。CSS 模块化的解决方案有很多,但主要有两类。</p>    <p>一类是彻底抛弃 CSS,使用 JS 或 JSON 来写样式。Radium, jsxstyle ,react-style 属于这一类。优点是能给 CSS 提供 JS 同样强大的模块化能力;缺点是不能利用成熟的 CSS 预处理器(或后处理器) Sass/Less/PostCSS, :hover 和 :active 伪类处理起来复杂。</p>    <p>另一类是依旧使用 CSS,但使用 JS 来管理样式依赖,代表是CSS Modules。CSS Modules 能最大化地结合现有 CSS 生态和 JS 模块化能力。发布时依旧编译出单独的 JS 和 CSS。它并不依赖于 React,只要你使用 Webpack,可以在 Vue/Angular/jQuery 中使用。</p>    <h3>启用 CSS Modules</h3>    <pre>  <code class="language-css">// webpack.config.js  css?modules&localIdentName=[name]__[local]-[hash:base64:5]</code></pre>    <p>加上 modules 即为启用, localIdentName 是设置生成样式的命名规则,[name]表示标签名,[local]表示类名,[hash:base64:5]是按照给定算法生成的序列码。</p>    <pre>  <code class="language-css">/* components/test.css */  .active {       color: red;  }  .disabled {      color: gray;  }    /* components/test.js */  import styles from './test.css';    console.log(styles);    elem.outerHTML = `<h1 class=${styles.active}>CSS Modules</h1>`</code></pre>    <p>生成的 HTML 是</p>    <pre>  <code class="language-css"><h1 class="h1--active-abc53"> Processing... </h1></code></pre>    <p>它将根据 styleName 的值在关联的 style 对象中查找对应的 CSS Modules,并为 ReactElement className 属性值添加相匹配的独一无二的 CSS 类名。</p>    <p>上例中 styles的consolelog 打印的结果是:</p>    <pre>  <code class="language-css">Object {    active: 'h1--active-abc53',    disabled: 'h1--disabled-def84',  }</code></pre>    <p>CSS Modules 对 CSS 中的 class 名都做了处理,使用对象来保存原 class 和定制处理后的 class 的对应关系。经过这样类名定制处理后,class 名基本就是唯一的,大大降低了项目中样式覆盖的几率。同时可以生成更短的 class 名,减少代码量。</p>    <h3>CSS Modules 使用</h3>    <p>局部变量和全局变量</p>    <ul>     <li>:local : 做 localIdentName 规则处理</li>     <li>:global : 样式编译后不变</li>    </ul>    <p>如果书写时不加,默认处理为 :local 。</p>    <pre>  <code class="language-css">.normal {    color: green;  }    :local(.normal) {    color: green;   }    /* 上面两个等价,默认给每个 class 名外加加了一个 `:local` */      /* 全局样式 */  :global {    .link {      color: green;    }    .box {      color: yellow;    }  }</code></pre>    <p>唯一哈希类名</p>    <p>开启CSS Modules时定义的规则 localIdentName=[name]__[local]-[hash:base64:5] 会控制对class名的处理, [hash:base64:5]定义的hash计算能保证类名的唯一性。</p>    <p>Compose 组合Class</p>    <p>很多时候我们都需要样式复用,在 CSS Modules 中,一个选择器可以继承另一个选择器的规则,这称为 composes 组合。</p>    <pre>  <code class="language-css">/* components/test.css */  .bg {    background-color: blue;  }    .title {    composes: bg;    color: white;  }    /* components/test.js */  import styles from './test.css';    elem.outerHTML = `<h1 class=${styles.title}>CSS Modules</h1>`</code></pre>    <p>生成的 HTML 为</p>    <pre>  <code class="language-css"><h1 class="h1--bg-fec53 h1--title-Ijf8"> Processing... </h1></code></pre>    <p>CSS和JS变量共享</p>    <p>:export 关键字可以把 CSS 中的 变量输出到 JS 中:</p>    <pre>  <code class="language-css">/* index.scss */  $primary-color: #f40;    :export {    primaryColor: $primary-color;  }    /* app.js */  import style from 'index.scss';    // 会输出 #F40  console.log(style.primaryColor);</code></pre>    <h3>CSS Modules使用特点</h3>    <ol>     <li>不使用选择器,只使用 class 名来定义样式</li>     <li>不层叠多个 class,只使用一个 class 把所有样式定义好</li>     <li>不嵌套class</li>     <li>所有样式通过 composes 组合来实现复用</li>    </ol>    <h3>旧项目的兼容</h3>    <ol>     <li>如果对一个元素使用多个 class,样式照样生效。</li>     <li>如何在一个 style 文件中使用同名 class ,编译后仍是同名的。</li>     <li>如果在 style 文件中使用了 id 选择器,伪类,标签选择器,所有这些选择器将不被转换,原封不动的出现在编译后的 css 中。即 CSS Modules 只会转换 class 名相关样式。</li>     <li>当类名经过编译生成新的随机类名后,可以解决命名冲突,但因为无法预知最终 class 名,不能通过一般选择器覆盖。现在一般给出的项目中的实践是可以给组件关键节点加上 data-role 属性,然后通过属性选择器来覆盖样式。</li>     <li>前端项目不可避免会引入 normalize.css 或其它一类全局 css 文件。使用 Webpack 可以让全局样式和 CSS Modules 的局部样式和谐共存。</li>    </ol>    <pre>  <code class="language-css">module: {    loaders: [{      test: /\.jsx?$/,      loader: 'babel'    }, {      test: /\.scss$/,      exclude: path.resolve(__dirname, 'src/styles'),      loader: 'style!css?modules&localIdentName=[name]__[local]!sass?sourceMap=true'    }, {      test: /\.scss$/,      include: path.resolve(__dirname, 'src/styles'),      loader: 'style!css!sass?sourceMap=true'    }]  }</code></pre>    <p> </p>    <p>来自:http://imweb.io/topic/586519b1b3ce6d8e3f9f99aa</p>    <p> </p>