开发公共组件遇到的样式问题

588 阅读4分钟

背景

最近接手了一个公共组件的开发,这个组件的作用是供接入方收集用户的使用体验,涉及红线,这里就不放出产品图片了

大体的功能:

  • 用户可以评星
  • 根据星级做出对应的操作,如:3星及以上则自动上报,然后弹出谢谢反馈
  • 3星以下视为不太满意,弹出不太满意原因:tags选项
  • 用户点击空白处或者叉掉组件自动上报提交

技术

  • react17
  • antd4.x
  • less

最后需要发布到npm,并支持sdk的方式引入

开发中遇到的问题

主要讲一下遇到的样式冲突问题,其实这些问题都是一环扣一环,有上一个问题才出现的下一个问题

前缀污染

修改antd组件的样式时在本地时生效的,打包后在平台上使用失效了 因为我这里使用了rate评分组件,所以我就拿这个组件举例子 应产品需求图,要在原来的rate组件上修改⭐️的颜色,自然而然先去查看对应的class ant-rate-star,找到对应的类名如下

image.png

所以理所当然的写出了如下代码

  .ant-rate-star-full {
    color: #FFD392;
  }

这样看起来没问题吧,但是在有些平台上使用就会出现样式不生效的问题。 于是打开平台的控制台先查看源码,发现上面的代码并没有丢失。只是类名的前缀变了

于是去请教平台的开发者,原来是他使用了antd提供的自定义前缀(如下图)。 image.png 同时自定义变量@ant-prefix导致css中的类名前缀都变了,知道问题后就好解决了,不就是外部定义的@ant-prefix污染了内部的吗,究其根本就是组件没有引入自己的@ant-prefix变量 于是加入以下代码就可以解决

@root-entry-name: 'default';
@import (reference) '~antd/es/style/themes/index.less';

上面代码执行完后,还会引入变量@ant-prefix,于是组件内部有自己的前缀,就不会受到外部的影响了

image.png

同类名污染

还是这个rate组件,有个使用组件的平台使用的antd版本是2.x版本,出现了下面的情况

image.png 查看dom元素发现2.x的⭐️是用的伪类实现的,而4.x使用的是svg实现的,所以同一个类名实现了两次⭐️

所以要从根本解决问题害得在上一步的基础上将antd的类名都更改

  • 在代码中加入前缀更改
<ConfigProvider prefixCls='dd-rc-feedback' iconPrefixCls='dd-rc-feedback-icon'>
</ConfigProvider>

这一步的作用是将antd的class中的前缀ant都变成定义的dd-rc-feedback

lessOptions: (options) => {
  options.lessOptions.modifyVars = {
    'ant-prefix': 'dd-rc-feedback',
    'iconfont-css-prefix': 'dd-rc-feedback-icon',
  }
  return options
}

这一步的作用是将less中的变量ant-prefix定义为dd-rc-feedback

经过以上两个操作,组件内以ant-prefix为前缀的类名的样式都不会影响到外部

变量污染

还记得在前面为了解决前缀污染,加入了两行代码吗?主要作用就是引入antd自定义的变量@ant-prefix 但是问题就出在这,引入这个变量的同时又引入了其他主题变量

image.png

这就会出现一个问题: 因为这些变量都是在全局定义的,如果使用组件的平台自定义antd的变量(如:自定义主题),就会出现变量被组件的变量覆盖(因为组件肯定是后引入的,会覆盖最初的变量)

要解决以上问题思路很简单,就是在控制一下组件中antd变量的作用范围,最直接的就是在前面加个类名。社区里有提供这么一个plugins:postcss-selector-namespace,他的作用就是可以在所有class再加个class,于是加入以下代码

// postcss.config.js
module.exports = {
  plugins: {
    'postcss-selector-namespace': {
      namespace(css) {
        return '.dd-rc-feedback'
      }
    }
  }
}

最终css就会这样

image.png

最终,经过以上3种方式的处理,达成了组件样式与宿主样式完全隔离的效果