问题示例className命名重复导致样式冲突我们先做一个问题来验证是否存在样式冲突:使用div元素在主应用和子应用上插入一段title,并使用相同的类名title对于两个div元素,分别在类中设置文字颜色,主应用的颜色值为黄色,子应用的颜色值为红色。由于子应用的样式加载晚于主应用的样式,因此主应用的样式将被覆盖。多个子app同时加载时也存在上述问题:同样条件的selector中可能还会有同名的className或添加的style,所以只有优先级最高的style才会在selector中生效结尾。为保证应用之间的样式互不影响,需要对应用之间的样式进行隔离。html和body标签的样式冲突。html和body标签在每个应用中都是独一无二的元素,它们的风格必然会影响到主应用的风格。解决方案为了解决上述样式冲突问题,通常有以下两种思路:通过样式命名&样式优先解决方案通过宿主环境隔离实现样式隔离样式命名&样式优先假设各个应用之间的样式className是全局唯一的,那么不同className下的样式肯定不会冲突。再加上样式优先级配合解决,可以解决标签选择器的样式冲突:比如在原来的className和标签选择器之前添加一个选择器标签选择器+属性选择器子应用改造需要的样式这里处理的也分为以下两种:UI组件库引入的全局样式等。默认情况下,UI组件库的prefixCls是一样的,但是他们提供了ConfigProvider,可以用来修改全局样式的prefixClsUI组件库:全局配置ConfigProvider-AntDesign[1]全局配置ConfigProvider|ArcoDesign[2]自定义样式使用BEM、CSSModules、CSSinJS等方式从其他应用中获取不同的选择器名称,避免样式冲突。或者直接使用postcss插件在编译时为所有样式添加前缀选择器。https://github.com/RadValentin/postcss-prefix-selector主应用在运行时统一转换样式如果我们不想或不能干涉子应用的打包配置,我们也可以在所有样式规则中添加前缀运行时通过主应用程序选择器来增加样式优先级。比如应用A的类选择器.title转换后变成#garfish_app_id_xxx.title,而#garfish_app_id_xxx是子应用最外层元素的id,所以要保证本应用下样式的优先级变高,并且让它只在当前应用程序下工作。当然,仅仅采用上述手段并不能解决子应用html和body标签对主应用的样式影响。如果细心的话,你可能已经发现,garfish会为每个子应用创建一个假的html和body元素,然后子元素对应的html的html和body样式就会应用到这个假的html和body元素上。Garfish使用garfish中的插件来支持运行时转换样式:import{GarfishCssScope}from'@garfish/css-scope';Garfish.run({plugins:[GarfishCssScope({fixBodyGetter:true,excludes:['appName'],}),],})具体源码实现在这里:https://github.com/modern-js-dev/garfish/tree/1f83e8fb35fd2ac12785fc7410015c3cd23c3bd2/packages/css-scope优点支持大部分样式隔离需求,可以是更省心同时处理UI组件库的全局样式和自定义样式。缺点在运行时处理样式时,会有一定的性能损失。如果其他子应用或者主应用使用!important...宿主环境隔离ShadowDOM依附隐藏在常规DOM下的节点称为ShadowDOM——它是Shadow根节点它是起始根节点。在这个根节点下面,它可以是任何元素,就像一个普通的DOM元素一样。它可以添加子节点,设置属性,通过方法给节点添加自己的样式,隐藏的DOM样式与DOM的其余部分完全隔离,类似于iframe的样式隔离效果。如何创建您可以使用shadowHostElement.attachShadow()方法将影子根附加到调用该方法的元素。它接受一个配置对象作为参数,该对象有一个mode属性,值可以是open或closed:letshadowRoot=shadowHostElement.attachShadow({mode:'open'});让shadowRoot=shadowHostElement.attachShadow({mode:'closed'});open表示可以在页面中通过JavaScript获取ShadowDOM,例如使用Element.shadowRoot属性:letshadowRoot=shadowHostElement.shadowRoot;如果模式设置为关闭,则elementRef.shadowRoot将返回null。这对于浏览器中的某些内置元素来说是正确的,例如
