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>