前端发展愈来愈快,这应该是每一个前端开发者的切身感觉,可是CSS 是前端领域中进化最慢的一块。ES678快速普及前端工程发愈发成熟,CSS 被被远远甩在了后面,JS语言模块已经标准化,CSS仍是在不断探索,同时这也是一个急需解决的问题。css
要是你之前还从未据说过CSS Modules,那么这篇就是专门写给你的。若是你了解过它,你就不必再看了,由于他真的很简单(很强大)。html
咱们都知道,CSS入门简单,深刻就比较难,样式简单维护难。CSS痛点也不少前端
一、CSS 的规则是全局的,任何一个组件的样式规则,都对整个页面有效。相信写css的人都会遇到样式冲突(污染)的问题。webpack
二、为了解决全局污染的问题,那就把class命名写长一点吧、加一层父级选择器、下降冲突的概率,那么CSS命名混乱了git
三、组件依赖管理不完全,组件应该相互独立,引入一个组件时,应该只引入它所须要的 CSS 样式。github
四、代码难以复用,出现了sass less 之类的工具web
前端发展是飞速的每天有新轮子。天然CSS 模块化的解决方案有不少,但主要有三类:算法
规范化CSS的解决方案如:BEM、OOCSS、AMCSS、SMACSS编程
完全抛弃 CSS,用 JavaScript 写 CSS 规则,styled-components 就是其中表明。sass
使用JS编译原生的CSS文件,使其具有模块化的能力,表明是 CSS Modules。
可是这些模块化方案都是各有优缺点,如命名约定:命名复杂、CSS in JS:缺少扩展、 CSS Modules固然也有一些缺点(你得先学会它再去谈优劣)。在众多解决方案中,没有绝对的优劣。仍是要结合本身的场景来决定。
CSS Modules不是将CSS改造的具备编程能力,而是加入了局部做用域、依赖管理,这偏偏解决了最大的痛点。能够有效避免全局污染和样式冲突,能最大化地结合现有 CSS 生态和 JS 模块化能力。
CSS Modules 很容易学。webpack 自带的 css-loader
组件,自带了 CSS Modules,经过简单的配置便可使用。
// webpack.config.js const path = require('path') module.exports = { entry: __dirname + '/src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', { loader: 'css-loader', options: { modules: true, } } ] } ] } } // 也可使用下面这种写法 // loader: "style-loader!css-loader?modules"
如今咱们来写个Button组件
/* Button.css */ .primary { background-color: #1aad19; color: #fff; border: none; border-radius: 5px; }
// Button.js import styles from './Button.css'; console.log(styles); // -> {primary: "yTXmm0isaXExoYiZUvKxH"} const Button = document.createElement('div') Button.innerHTML = `<button class=${styles.primary}>Submit</button>` export default Button // index.js import Button from './components/Button' const app = document.getElementById('root') app.appendChild(Button)
生成HTML为
<div id="root"> <div> <button class="yTXmm0isaXExoYiZUvKxH">Submit</button> </div> </div> <!-- yTXmm0isaXExoYiZUvKxH为CSS Modules自动生成的class类名 -->
CSS Modules 对 CSS 中的 class 名都作了处理,使用对象来保存原 class 和混淆后 class 的对应关系。CSS Modules自动生成的class类名基本就是惟一的,大大下降了项目中样式覆盖冲突的概率。
GitHub 示例库 https://github.com/liuxing/css-modules-demo 经过commit 记录来查看
css-loader
默认的哈希算法是[hash:base64]
,从前面咱们能够发现.primary
被编译成了 yTXmm0isaXExoYiZUvKxH 这样的字符串。这名字也没风格了别担忧,css-loader 为咱们提供了localIdentName
参数指定生成的名字格式。localIdentName
的默认值是[hash:base64]
。
... { loader: 'css-loader', options: { modules: true, localIdentName: '[name]__[local]--[hash:base64:5]' } } // 或者 loader: 'style-loader!css-loader?modules&localIdentName=[name]__[local]--[hash:base64:5]' ...
BEM代码规范再也不是必须的 熟悉BEM的同窗可能发现了上面的命名和BEM有些神似, 虽然它的命名有点奇特,可是 BEM 被很是多的大型项目和团队采用,这是一种很好的实践。固然了随便怎么写均可以结合本身的场景来决定,在CSS module中再也不须要遵照BEM规范。
经过前面的例子能够感觉到CSS module处理CSS的方式。如今咱们从头来讲做用域。
CSS不少问题都是由于全局做用域引发的,怎么样才能产生局部做用域?经过前面CSS module的例子咱们发现它思路很简单就是生成惟一的class类名。CSS module将class转换成对应的全局惟一hash值来造成局部做用域。使用了 CSS Modules 后,就至关于给每一个 class 名外加了一个 :local
这是默认的,也能够显式使用
固然,若是你想切换到全局模式,CSS Modules 容许使用:global(.className)
的语法,声明一个全局规则。凡是这样声明的class
,都不会被编译成哈希字符串。
/* Button.css */ :global(.btn) { color: #fff; border: none; border-radius: 5px; } .primary { background-color: #1aad19; } /* 与上面不加`:local`等价 显式的局部做用域语法 */ :local(.warn) { background-color: #e64340 }
经过 GitHub 示例库 https://github.com/liuxing/css-modules-demo 的commit 记录来查看
对于样式复用,CSS Modules 提供了 composes
组合 的方式来处理。一个选择器能够继承另外一个选择器的规则
/* Button.css */ .btn { /* 全部通用的样式 */ color: #fff; border: none; border-radius: 5px; box-sizing: border-box; } .primary { composes: btn; background-color: #1aad19; }
Button.js
import styles from './Button.css'; console.log(styles); const Button = document.createElement('div') Button.innerHTML = `<button class="${styles.primary}">Submit</button>` export default Button
生成的 HTML 变为
<div id="root"> <div> <button class="Button__primary--yTXmm Button__btn--nx67B">Submit</button> </div> </div>
咱们发如今 .primary
中 composes 了 .btn
,编译后 .primary
会变成两个 class。
composes 还能够也能够继承组合其余CSS文件里面的规则
/* author.css */ .shadow { box-shadow: 0 0 20px rgba(0, 0, 0, .2) }
Button.css
··· .primary { composes: btn; composes: shadow from './author.css'; background-color: #1aad19; } ···
这是个很强大方便的功能,CSS Modules团队成员认为composes
是CSS Modules里最强大的功能:
For me, the most powerful idea in CSS Modules is composition, where you can deconstruct your visual inventory into atomic classes, and assemble them at a module level, without duplicating markup or hindering performance.
为了追求简单可控,做者建议遵循以下原则:
composes
组合来实现复用可是建议只是建议,CSS Modules 并不强制你必定要这么作。怎么舒服怎么来
CSS Modules 很好的解决了 CSS 目前面临的一些痛点以及模块化难题,同时也支持与 Sass/Less/PostCSS 等搭配使用。
不管是经过遵循的命名标准化的规范,仍是使用本文介绍的CSS Modules,目的都是同样:可维护的css代码。具体使用不是有仍是要结合本身的场景来决定。适合的才是最好的
你们能够关注个人公众号,一块儿玩耍。有技术干货也有扯淡乱谈,关注回复[888]领取福利
左手代码右手砖,抛砖引玉