- Published on
如何实现样式隔离?
- Authors

- Name
- 叫我小N就好啦
- GitHub
- @MinorN
如何实现样式隔离?
什么是样式隔离?
不同组件、模块之间维护自己的样式,不影响其他组件、模块的样式
因为原生的 css 中,不支持局部作用域,所以说需要实现样式隔离
为什么需要样式隔离
- 防止全局污染
- 依赖管理混乱
- 顺序、层叠都可能会导致样式冲突
这样就会导致 css 急速膨胀并且难以维护,牵一发而动全身
如何实现样式隔离
BEM 命名规则
只是一个命名规则,class 类目按照规定的方式进行命名
Block--Element__Modifier 按照这个规则(块--元素**修饰符),例如:article--title**color
但是这个方法的缺点也很明显,完全受到个人控制,有成本
CSS Module
使用一些工程化的工具来把 class 设置一个类似局部作用域的概念
.title {
color: red;
}
// 转换后
._cqacqca {
color: red;
}
原理也很简单,就是使用 css-loader + modules=true ,把每个 class 转换成包含文件名和哈希值的一个唯一标识符,这样就能够保证不同 css 模块没有冲突,简单易用,可以使用工具;但是缺点也很明显,代码可读性差,难以 debug,同时不支持变量
CSS IN JS
css in js 是将 css 直接嵌入到 js 中的模式,比如说:React
优点:使用的工具很多,比如 styled-components等,同时样式和组件强相关
缺点:大多都是运行时产生样式代码,所以说运行时开销较大
iframe
iframe 拥有自己独立的文档模型,全局作用域、样式等,但是 iframe 的缺点很多,不建议使用
缺点:
- 性能开销,每一个
iframe都是一个完整的文档环境,会有额外的性能开销 - 通信机制复杂,需要使用
postMessage来进行通信 SEO、可访问性收到影响- 跨域受限
web component
用于封装 html 结构、js 逻辑的 api
原理:得益于 Shadow DOM 的特性,web component 内部可以创建一个封闭的 DOM 环境,内部的样式不会泄漏到外部,外部的也不会影响内部
<!DOCTYPE html>
<html>
<head>
<title>web component</title>
<style>
.wrapper {
color: red;
background: yellow;
}
</style>
</head>
<body>
<div class="wrapper">这是外部的元素,应用了外部样式</div>
<my-custom-element></my-custom-element>
<script>
class MyCustomElement extends HTMLElement {
constructor() {
super() // 总是首先调用 super() 构造函数
// 创建一个 shadow root
const shadow = this.attachShadow({ mode: 'open' })
// 添加一些 HTML 内容到 shadow root
const wrapper = document.createElement('div')
wrapper.setAttribute('class', 'wrapper')
wrapper.textContent = '这是我的自定义元素内容!'
// 在 Shadow DOM 中定义样式
const style = document.createElement('style')
style.textContent = `
.wrapper {
color: white;
background: blue;
padding: 10px;
border-radius: 8px;
}
`
// 将样式和元素附加到 shadow DOM
shadow.appendChild(style)
shadow.appendChild(wrapper)
}
}
// 定义新的元素
customElements.define('my-custom-element', MyCustomElement)
</script>
</body>
</html>
web component 浏览器原生支持,但是缺点也很明显
缺点:
- 兼容性:一些较老的浏览器不支持
- 学习曲线大
- 工具链生态没有
Vue、React好 - 大量
web component需要考虑性能 - 管理维护复杂
Vue scoped
这是 Vue 提供的样式隔离手段,通过在 style 标签上添加 scoped 属性即可,但是只适用于 Vue 框架
css @layer 规范
@layer 声明了一个层叠层,同一层内的规则将级联在一起
@layer framework, components, themes;
// 这里就定义了优先级,从左往右,优先级慢慢提高
@layer framework{
p{
color: red;
}
}
@layer components{
p{
color: blue;
}
}
@layer themes{
p{
color: black;
}
}
// 最后 color 会显示 black
优点:
- 组织性更好
- 官方定义
- 明确的层叠控制
- 模块化
- 维护简单
缺点:
- 兼容性
- 难以调试