likes
comments
collection
share

微前端中常见的几种CSS隔离实现方案

作者站长头像
站长
· 阅读数 16

微前端中,让人头疼的一个问题,CSS样式覆盖和冲突问题。

如何能让子应用的样式保持独立,业界采用了各种不同的方案,这里做一下汇总,每种方案都有其可取之处,但也都是在特定场景下的解决方案,了解这些实现方案,能更好的处理问题。

一、BEM

CSS 命名规范,根据子应用提前约定CSS前缀。

原理:通过制定一套命名规范,避免样式之间的相互干扰,提高样式表的可维护性。

  • 优点是实现简单、清楚。
  • 不足:1、容易突破规范。2、人肉维护成本高

具体用法:常见的 CSS 命名规范有 BEM、OOCSS、SMACSS 等。例如,使用 BEM 命名规范,可以将一个按钮的 HTML 和 CSS 代码写成这样:

BEM规范:Block、Element、Modifier

  • __:双下划线用来连接块和块的子元素,左右的元素可以单独作为类
  • - :仅作为连字符使用,连接块或元素或修饰符的多个单词(也可以直接写成驼峰式),不能拆分,两个属性描述一个类
  • --:双中划线用来连接块或元素的状态(也可使用‘_’单下划线表示,本文以'--'方式介绍):不同的属性值
<div class="search-box search-box--hover">
    <div class="search-box__item"></div>
    <div class="search-content__item"></div>
    <button class="search-box__button"></button>
</div>

对应的CSS文件

.search-box {
    display: inline-block;
    border-radius: 5px;
    font-size: 16px;
}
item {
    padding: 10px;
}
.search-box--hover {
    cursor: pointer;
}
.search-box__item {
    display: inline-block;
    border-radius: 5px;
    font-size: 16px;
    padding: 10px;
}
.button {
    background-color: blue;
    color: white;
}

二、CSS Module

通过import导入css变量,引用css,结合webpack,css-loader支持

优点是:实现简单、引用不符合使用习惯

index.module.css

.color-red {
    color: red;
}

app.tsx

// 不使用 import 
// './index.module.css';

// 使用 CSS Modules 
import styles from './index.module.css'; 

function App() {
  return (
    <div className='color-red'>
      <div className={styles['color-red']}>
        站点头部颜色红色
      </div>
      <Dashboard />
    </div>
  );
}

参考:阮一峰CSS Modules 用法教程

三、CSS in JS

原理:将 CSS 样式表编写成 JavaScript 对象,以避免样式之间的相互干扰。

  • 优点:实现了CSS的独立
  • 不足:CSS嵌入JS耦合太深,维护不方便

具体用法:常见的 CSS in JS 库有 styled-componentsEmotionJSS 等。

例如,使用 styled-components,可以将一个按钮的样式写成这样:

button.js

import styled from 'styled-components';

const Button = styled.button`
  display: inline-block;
  padding: 10px 20px;
  border-radius: 5px;
  font-size: 16px;

  &.large {
    font-size: 20px;
  }

  &.primary {
    background-color: blue;
    color: white;
  }
`;

demo.js

import Button from './button.js'
function Demo(){
    return <Button></Button>
}

四、Shadow DOM

CSS Shadow DOM 是一种将样式隔离到 Web 组件内部的技术,它可以让组件内部的样式不会影响到外部的样式,从而实现前端微服务中的 CSS 样式隔离。

具体来说,Shadow DOM 允许开发人员创建一个封装了 HTML、CSS 和 JavaScript 的组件,这个组件内部的样式只会影响这个组件内部的元素,不会影响到其他组件或页面上的元素。这样可以避免样式之间的相互干扰,提高样式表的可维护性和可重用性。

使用 CSS Shadow DOM 可以通过以下步骤实现:

  1. 创建一个 Shadow DOM:
const shadowRoot = element.attachShadow({ mode: 'open' });
  1. 在 Shadow DOM 中定义 HTML、CSS 和 JavaScript:
const template = document.createElement('template');
template.innerHTML = `

  <style>
    /* Shadow DOM styles */
  </style>

  <div class="my-component">
    <!-- Shadow DOM HTML -->
  </div>
`;
shadowRoot.appendChild(template.content.cloneNode(true));
  1. 在外部使用组件时,只需要引入组件的 JavaScript 文件即可:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My App</title>
</head>
<body>
  <my-component></my-component>
  <script src="my-component.js"></script>
</body>
</html>

全局的样式还是会被主应用的样式覆盖,如果主应用的CSS样式权重更高的话。

五、CSS预处理器

原理:通过使用预处理器,将 CSS 编写成更加易于维护的代码,避免样式之间的相互干扰。

具体用法:常见的 CSS 预处理器有 Sass、Less、Stylus 等。例如,使用 Sass,可以将一个按钮的样式写成这样:

$button-padding: 10px 20px;
$button-border-radius: 5px;

.button {
    display: inline-block;
    padding: $button-padding;
      border-radius: $button-border-radius;
    font-size: 16px;

&--large {
    font-size: 20px;
}

&--primary {
    background-color: blue;
    color: white;
}

六、CSS后处理器

1、postcss、autoprefixer

/* 输入样式 */ 
.box { display: flex; } 
/* 经过处理后的样式 */ 
.box { 
    display: -webkit-box; 
    display: -ms-flexbox; 
    display: flex; 
}

2、postcss-modules

/* 输入样式 */ 
.box { color: red; } 
/* 经过处理后的样式 */ 
.box_1e9v8z6 { color: red; }

webpack

module.exports = {
    plugins: [
        require('autoprefixer'),
        new webpack.LoaderOptionsPlugin({ 
            options: { 
            postcss: [ 
                require('postcss-modules')() 
            ] 
        }})
    ]
}

3、在Vue中,只需要在style上添加scoped属性

<template>
    <div class="container"> 
        <h1>这是一个组件</h1> 
        <p>这是组件的内容</p> 
    </div> 
</template> 
<style scoped> 
    .container { 
        background-color: #f5f5f5; 
        padding: 20px; 
    } 
    h1 { color: #333; } 
    p { color: #666; } 
</style>