当前比较流行的微前端架构方案,其中要解决的问题之一是处理子模块之间的冲突,其中包括js冲突、css冲突等,本周着重总结一下css冲突解决方案。
因为css并没有作用域这个说法,只要规则匹配上就会被应用到元素上面,所以如果系统中涉及到N个子系统的协同开发时,就难以避免的会出现样式冲突、覆盖的情况。 查询资料后,发现有以下几个方法处理。
下面分别从上图的六个方法来讲述
-
BEM 简单解释一下BEM,block__element--modifiedmoment,举例: .select__options--active、.dropdown--menu__item--active等,就是这种方式可以请清晰的看出这个类名的用途,可读性较好,缺点是比较依赖约定,难免会出现不符合约定的命名方式。在编写组件过程中经常用到。
-
vue scope
我们很经常编写的vue 组件,用的是这种方式隔离,我们看个例子。 编译之前:
<style lang="scss" scoped>
.sidebar-logo-container {
position: relative;
width: 100%;
height: 50px;
line-height: 50px;
background: #2b2f3a;
text-align: center;
overflow: hidden;
}
</style>
编译后样式:
// dom节点
<div data-v-1039e2f0="" class="sidebar-logo-container"><img data-v-1039e2f0="" src="https://km.woa.com/gkm/api/img/cos-file-url?url=https%3A%2F%2Fkm-pro-1258638997.cos.ap-guangzhou.myqcloud.com%2Ffiles%2Fphotos%2Fpictures%2Fmobile_for_extranet_img%2Fimage-1251917893.cos.ap-guangzhou.myqcloud.com%2Fpvp-admin%2F1619431192004.jpg&is_redirect=1" alt="logo"></div>
// 对应样式
.sidebar-logo-container[data-v-1039e2f0] {
position: relative;
width: 100%;
height: 50px;
line-height: 50px;
background: #2b2f3a;
text-align: center;
overflow: hidden;
}
以上是vue style在编译过程中对每个样式加上了独一无二的属性选择,通过对属性选择参数的控制,保证样式的全局唯一性。
- 通过shadow dom来完成。
看下mdn上的定义
然后我们测试一下:
const shadowDomContainer = document.getElementById('shadow-dom');
const shadow = shadowDomContainer.attachShadow({ mode: 'open' });
shadow.innerHTML = `
<span class="container">这个一个shadow dom</span>
<style type="text/css">
.container {
background: red;
}
</style>
`
看下效果:
- css module
通过webpack工具结合css-loader来实现css样式隔离。看下例子
.title {
color: green;
composes: blue from './color.css';
composes: red;
border-bottom: 1px solid #ccc;
padding-bottom: 20px;
}
编译后
// dom节点
<h2 class="src-styles-index__title--3XpLk src-styles-color__blue--3WlK8 src-styles-index__red--1ihPk">CSS Modules</h2>
// css样式
.src-styles-index__title--3XpLk {
color: green;
border-bottom: 1px solid #ccc;
padding-bottom: 20px;
}
可以看出,这种方式就是把BEM通过工具化方式实现。开启方式如下:
{
test: /\.css$/,
use: [
{ loader: "style-loader" },
{
loader: "css-loader",
options: {
!!#ff0000 modules: true,!!
// camelCase: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]'
}
}
]
},
- 预处理器,通过sass、less、stylus等预处理器,开发者可以编写自己的应用规则,实现dom层级嵌套结构,这种方式的样式源码更加一目了然。这里就不多介绍。
- css in js. 这种方式,我理解是基于封装的思想,把相同职责的模块代码都放置在一起,在组件封装和代码可读性上有较大提升。跟传统的关注点分离的思想有所不同。 这里看个例子,有些过react、react-native代码的同学,对这个应该比较熟悉。
const style = {
'color': 'green',
'fontSize': '24px'
};
const handle = () => alert('hellow');
ReactDOM.render(
<h1 style={style} onclick={handle}>
Hello, world!
</h1>,
document.getElementById('example')
);
这样子就把组件所需要的信息都封装到内部,可以更加方便的复用组件内容。