class属性不参与样式隔离,仅作为选择器载体;真正隔离需依赖运行时劫持style/link、重写css选择器或shadow dom等机制。

class属性本身不参与样式隔离,只作为选择器载体
给子应用元素加 class="btn" 或 class="header primary",不会自动触发任何隔离逻辑。浏览器照常匹配全局 CSS 规则,比如主应用的 .btn { color: blue } 仍会生效——哪怕子应用自己也写了 .btn { color: red },最终谁后加载、权重高,谁赢。
手动加 class 前缀没用,除非构建时重写所有 CSS
你写 <div class="subapp-a-btn"></div> 并配一条 .subapp-a-btn { color: red },看似“隔离”了,但问题在于:
- 第三方库(如 Ant Design)的
.ant-btn不会自动变成.subapp-a-ant-btn,照样穿透 - 子应用里用 CSS-in-JS 动态生成的类名(如
css-123abc)根本不受控 - 所有依赖后代选择器的规则(如
.layout .btn)依然能命中,前缀只挡住了直接类名匹配 - 如果子应用 CSS 是通过
@import或url()加载的,构建工具若没递归处理,前缀就漏掉了
真正起效的 class 隔离必须配合运行时注入或构建时插件
qiankun 的 strictStyleIsolation: true 或 MicroApp 的样式沙箱,并不是靠你写 class 来工作的。它们实际做的是:
- 劫持子应用动态插入的
<style></style>标签,把其中所有.btn改成[data-qiankun="sub-app-a"] .btn - 拦截
<link rel="stylesheet">请求,返回重写后的 CSS 内容(含前缀) - 对已挂载的 DOM,用 MutationObserver 监听新插入的 style/link 节点,实时重写
- 不碰你手写的
class属性值——它只改 CSS 选择器,不改 HTML class
所以,class 在这里只是被“借用”的字符串,不是开关,也不是作用域边界。
容易被忽略的细节:class 冲突发生在 DOM 查询阶段,不止是渲染
即使样式被隔离了,JS 仍可能因 class 名冲突出错:
-
document.querySelector('.modal-overlay')可能拿到其他子应用的节点(如果没限定 scope) - React/Vue 组件内用
className="modal-overlay",若没配置getContainer指向 shadowRoot,弹窗仍挂到document.body,class 就暴露在全局上下文 - 子应用用了
getElementsByClassName('btn'),结果遍历到主应用的按钮——class 不是命名空间,只是字符串匹配
class 的“隔离感”全是假象,它既不封装 DOM,也不约束 JS 查询。真要切断,只能靠 attachShadow({ mode: 'closed' }) + adoptedStyleSheets + 显式限定查询范围。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











