一、BEM
1.1 简介
BEM是一种css命名方法论,意思是块(Block)、元素(Element)、修饰符(Modifier)的简写
这种命名方法让CSS便于统一团队开发规范和方便维护
以 .blockelement—modifier或者说block-nameelement-name—modifier-name形式命名,命名有含义,也就是模块名 + 元素名 + 修饰器名
如.dropdown-menu__item—active
社区里面对BEM命名的褒贬不一,但是对其的思想基本上还是认同的,所以可以用它的思想,不一定要用它的命名方式
1.2 应用场景
1.3 优缺点分析
优点:
- 人为严格遵守BEM规范,可以解决无作用域样式污染问题
可读性好,一目了然是那个dom节点,对于无用css删除,删除了相应dom节点后,对应的css也能比较放心的删除,不会影响到其他元素样式
缺点
人为依赖约定,容易出错
- 命名相对复杂
二、CSS modules
2.1 简介
css-modules 将 css 代码模块化,可以避免本模块样式被污染,并且可以很方便的复用 css 代码所有的类名和动画名称默认都有各自的作用域的CSS文件。
CSS Modules既不是官方标准,也不是浏览器的特性,而是在构建步骤(例如使用Webpack,记住css-loader)中对CSS类名和选择器限定作用域的一种方式(类似于命名空间)
依赖webpack css-loader,配置如下,现在webpack已经默认开启CSS modules功能了
{
test: /.css$/,
loader: "style-loader!css-loader?modules"
}
我们先看一个示例:
将CSS文件style.css引入为style对象后,通过style.title的方式使用title class:
import style from './style.css';
export default () => {
return (
<p className={style.title}>
I am KaSong.
</p>
);
};
对应style.css:
.title {
color: red;
}
打包工具会将style.title编译为带哈希的字符串
<h1 class="_3zyde4l1yATCOkgn-DBWEL">
Hello World
</h1>
同时style.css也会编译:
._3zyde4l1yATCOkgn-DBWEL {
color: red;
}
这样,就产生了独一无二的class,解决了CSS模块化的问题
使用了 CSS Modules 后,就相当于给每个 class 名外加加了一个 :local,以此来实现样式的局部化,如果你想切换到全局模式,使用对应的 :global。
:local 与 :global 的区别是 CSS Modules 只会对 :local 块的 class 样式做 localIdentName 规则处理,:global 的样式编译后不变
.title {
color: red;
}
:global(.title) {
color: green;
}
可以看到,依旧使用CSS,但使用JS来管理样式依赖, 最大化地结合现有 CSS 生态和 JS 模块化能力,发布时依旧编译出单独的 JS 和 CSS
2.2 优缺点分析
优点
- 能100%解决css无作用域样式污染问题
-
缺点
需要频繁引入 CSS 文件 (有类似 react-css-modules 之类的模块解决)
- 没有变量,需要结合预处理器
- 编译后代码可读性差,hash 值不方便 debug
三、CSS in JS
3.1 简介
核心思想是把CSS直接写到各自组件中,也就是说用JS去写CSS,而不是单独的样式文件里
这跟传统的前端开发思维不一样,传统的原则是关注点分离,如常说的不写行内样式、不写行内脚本
CSS-in-JS不是一种很新的技术,可是它在国内普及度好像并不是很高,它当初的出现是因为一些component-based的Web框架(例如 React,Vue 和 Angular)的逐渐流行,使得开发者也想将组件的CSS样式也一块封装到组件中去以解决原生CSS写法的一系列问题
使用 React 改写如下 ```javascript const style = { ‘color’: ‘red’, ‘fontSize’: ‘46px’ };
const clickHandler = () => alert(‘hi’);
ReactDOM.render(
Hello, world!
, document.getElementById(‘example’) );
上面代码在一个文件里面,封装了**结构、样式和逻辑**,完全违背了"关注点分离"的原则<br />但是,这有利于组件的隔离。每个组件包含了所有需要用到的代码,不依赖外部,组件之间没有耦合,很方便复用。
<a name="ZmKw1"></a>
### 3.2 CSS in JS 与"CSS 预处理器"(比如 Less 和 [Sass](https://link.juejin.cn/?target=https%3A%2F%2Fwww.ruanyifeng.com%2Fblog%2F2012%2F06%2Fsass.html),包括 PostCSS)有什么区别
CSS in JS 使用 JavaScript 的语法,**是 JavaScript 脚本的一部分**,不用从头学习一套专用的 API,也不会多一道编译步骤,但是通常会在运行时动态生成CSS,造成一定运行时开销
<a name="HNQoF"></a>
### 3.3 优缺点分析
<a name="BxE1c"></a>
#### 优点
- **没有无作用域问题样式污染问题**通过唯一CSS选择器或者行内样式解决
- **没有无用的CSS样式堆积问题**CSS-in-JS会把样式和组件绑定在一起,当这个组件要被删除掉的时候,直接把这些代码删除掉就好了,不用担心删掉的样式代码会对项目的其他组件样式产生影响。而且由于CSS是写在JavaScript里面的,我们还可以利用JS显式的变量定义,模块引用等语言特性来追踪样式的使用情况,这大大方便了我们对样式代码的更改或者重构
- **更好的基于状态的样式定义**CSS-in-JS会直接将CSS样式写在JS文件里面,所以样式复用以及逻辑判断都十分方便
<a name="AkNwk"></a>
#### 缺点:
- **一定的学习成本**
- **代码可读性差**
- **运行时消耗**
- 不能结合成熟的CSS预处理器(或后处理器)Sass/Less/PostCSS,:hover 和 :active 伪类处理起来复杂
<a name="bmiUH"></a>
## 四、预处理器
<a name="PsOlo"></a>
### 4.1 简介
**CSS 预处理器**是一个能让你通过预处理器自己独有的语法的程序<br />市面上有很多CSS预处理器可供选择,且绝大多数CSS预处理器**会增加一些原生CSS不具备的特性**,例如
- 代码混合
- 嵌套选择器
- 继承选择器
这些特性让CSS的结构更加具有可读性且易于维护<br />常见的预处理器:
- [Sass](https://link.juejin.cn?target=https%3A%2F%2Fsass-lang.com%2F)
- [LESS](https://link.juejin.cn?target=https%3A%2F%2Flesscss.org%2F)
- [Stylus](https://link.juejin.cn?target=http%3A%2F%2Fstylus-lang.com%2F)
- [PostCSS](https://link.juejin.cn?target=http%3A%2F%2Fpostcss.org%2F)
<a name="pd3vK"></a>
### 4.2 优缺点分析
<a name="ivYgw"></a>
#### 优点:
- 利用嵌套,人为严格遵守嵌套首类名不一致,可以解决无作用域样式污染问题
- 可读性好,一目了然是那个dom节点,对于无用css删除,删除了相应dom节点后,对应的css也能比较放心的删除,不会影响到其他元素样式
<a name="uL9hw"></a>
#### 缺点
- 需要编译工具处理
<a name="PmbXG"></a>
## 五、Shadow DOM
<a name="GGkuI"></a>
### 5.1 简介
![](https://cdn.nlark.com/yuque/0/2022/webp/1125546/1650943788028-f41c9a6d-ff03-46f5-8aaa-d8fbd5a4c679.webp#clientId=u1880087a-ee69-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u97d7f45c&margin=%5Bobject%20Object%5D&originHeight=939&originWidth=1304&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=ud79c2772-e413-4575-862d-57963aa1271&title=)
<a name="X08Pl"></a>
### 5.2 优缺点分析
<a name="vHrIG"></a>
#### 优点
- 浏览器原生支持
- 严格意义上的样式隔离,如iframe一样
<a name="bvffg"></a>
#### 缺点
- 浏览器兼容问题
- 只对一定范围内的dom结构起作用,上面微前端场景已经说明
> 普通业务开发我们还是用框架、如Vue、React;Shadow DOM适用于特殊场景,如微前端
<a name="ggOL6"></a>
## 六、vue scoped
当 <style> 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素<br />使用 scoped 后,**父组件的样式将不会渗透到子组件中**<br />不过一个子组件的根节点会同时受其父组件的 scoped CSS 和子组件的 scoped CSS 的影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式,父租价利用深度作用选择器影响子组件样式<br />可以使用 >>> 操作符:
```javascript
<style scoped>
.a >>> .b { /* ... */ }
</style>
有些像 Sass 之类的预处理器无法正确解析 >>>。这种情况下你可以使用 /deep/ 或 ::v-deep 操作符取而代之——两者都是 >>> 的别名,同样可以正常工作
总结
社区通常的样式隔离方案,以下两种
- BEM+预处理器
- CSS Moduls + 预处理器