Open fi3ework opened 4 years ago
这样做好像 html 和 body 标签下的样式无法指定,主要影响的是 font,antd 的会被全局样式所覆盖。不过如果这点不重要的话,其他样式看起来的都是没什么问题的,感谢提供的方案。
多说一句,antd 4.7.0 里面不再是 base.less 设定全局样式,所有的全局样式都移动到了 global.less 这个文件里,base.less 已经限定了作用域,所以如果要改写 antd.less 的话,需要改成如下内容:
@import '~antd/lib/style/themes/index.less';
@import '~antd/lib/style/mixins/index.less';
*[class*='ant-'] {
@import '~antd/lib/style/core/global.less';
}
@import '~antd/lib/style/core/base.less';
@import '~antd/lib/style/core/iconfont.less';
@import '~antd/lib/style/core/motion.less';
@import '~antd/lib/style/components.less';
虽然确保了antd组件样式不影响全局的,但是提高了antd样式的层级,导致后面如果要写自己的私有样式,一个类根本不够,会被antd的[class *=ant-]h1这种的覆盖掉
虽然确保了antd组件样式不影响全局的,但是提高了antd样式的层级,导致后面如果要写自己的私有样式,一个类根本不够,会被antd的[class *=ant-]h1这种的覆盖掉
直接 !important
不错的方案,学习了
用 patch-package
打个补丁,直接将 node_modules/antd/lib/style/core/index.less
改成下面这样就行:
@import '../mixins/index';
@import 'base';
*[class*='ant-'] {
@import 'global';
}
@import 'iconfont';
@import 'motion';
步骤少,很方便。
用
patch-package
打个补丁,直接将node_modules/antd/lib/style/core/index.less
改成下面这样就行:@import '../mixins/index'; @import 'base'; *[class*='ant-'] { @import 'global'; } @import 'iconfont'; @import 'motion';
步骤少,很方便。
兄弟,试了下,不行呀,和antd版本有关系吗?
用
patch-package
打个补丁,直接将node_modules/antd/lib/style/core/index.less
改成下面这样就行:@import '../mixins/index'; @import 'base'; *[class*='ant-'] { @import 'global'; } @import 'iconfont'; @import 'motion';
步骤少,很方便。
兄弟,试了下,不行呀,和antd版本有关系吗?
应该没关系,你按照 patch-package 的文档操作,生成 patches 文件夹及对应的文件了吗?
我写了一个less插件来自动移除antd的全局样式antd/lib/style/core/global.less
: https://github.com/csr632/less-plugin-remove-antd-global-styles
能够与vite, webpack, rollup以及babel-plugin-import一起使用。
背景
由于某些原因,我们团队负责在 GitLab 上做二次开发,简单理解就是在 GitLab 上挂个 DOM 渲染用 React 写的一些组件,组件库选择了 antd,尴尬的是引入之后发现,GitLab 自身是带一套全局样式的,而 antd 又带了一套全局样式,导致 GitLab 的部分样式被覆盖,如图: a 标签颜色被 antd 覆盖:
checkbox 细微的样式错乱及大小改变:
原因
antd 的全局样式也不是一天两天的问题了,在社区中已经有很多讨论(#4331 #9363 #13459),但直到今天也没有进展。因为 Ant-Design 是一套设计语言,所以 antd 会引入一套 fork 自 normalize.css 的浏览器默认样式重置库。
引入全局样式的这个文件是 style/core/base.less,就是这个 base.less 会对各种元素的默认样式一顿格式化,截取一段:
下图为 antd 的 CSS 打包时的依赖关系,这张图有助于我们理清怎样才能避免把 base.less 引入。
解决核心问题
核心问题就是 base.less 这个文件对全局样式的侵入。那这个文件可以不要吗?不行,antd 的组件样式都是建立在这个格式化后的样式上的,不引这个文件样式就错位了(如下图),所以要在不影响全局样式的条件下引入。
并且,一般我们需要收敛 antd 全局样式时,都是因为当前页面存在另一套全局样式库(比如笔者遇到的 GitLab 的全局样式),我们需要达到的目的可以进一步变为 「收敛 base.less,并保证外部的全局样式无法轻易覆盖 antd 的样式」。
简单限定 base.less
之前社区中出现过将 base.less 外面套一层
.ant-container
的方案,但一个显著的缺陷就是提高了 base.less 中样式的权重导致样式错位。全面提高 ant- 的优先级
但是限定 base.less 这个思路是没有错的,base.less 需要被套一层「作用域」,那再给所有已有的 antd 组件提高权重保证原有的选择器优先级不变就好了。
幸运的是,antd 相关的组件都至少会有一个以
ant-
开头的 class,我们只要利用好这个特点及 CSS 属性选择器即可达到目的。流程如下:
*[class*='ant-']
限定其样式的「作用域」。这一步将全局样式限定在了所有有ant-
的 class 的元素里。提高完了 base.less 的权重,再来提升组件的样式的权重,此举还能间接提升所有 antd 的样式的权重,避免外部的全局样式对 antd 造成侵入。
既然是改样式,那就用 CSS 界的 babel —— PostCSS,写个 PostCSS 插件,https://github.com/fi3ework/postcss-rename-selector ,将所有
.ant
开头的类选择器都同样升高即可,利用的是 postcss-selector-parser 这个 PostCSS 官方提供的解析选择器的库,过滤出「第一个以 ant- 开头的类选择器」,在其前面添加一个属性选择器[class*='ant-']
,如果这个选择器排在当前 rule 的第一个或者前面是一个 combinator,则再加一个通配符*
,这个同上面给 base.less 添加的选择器,两者同时提高相同权重既维持原有优先级不变。另外,如果某些元素虽然不在 antd 的组件里,但是也想走 antd 的全局样式,只需在这些元素的最外层套一个 class
className="ant-whatever"
,只要是ant-
开头的就可以。这个 antd 的配置已经作为 preset 提供了,如果想使用直接引入即可
效果如图:
使用方式
建了 demo 仓库,下面几种的方式在 demo 仓库中都可以找到:https://github.com/fi3ework/restricted-antd-style-demo
方式 1:删除 base.less 一把梭
全量
思路是:在 post-install 阶段将
antd/lib/style/core/index.less
引入的@import base;
这一行直接删掉,然后手动引入我们自己魔改的 base.less。步骤:
antd/lib/style/core/index.less
,这边已经有实现 https://github.com/ant-design/ant-design/issues/9363#issuecomment-598091517import 'antd/dist/antd.less'
看下效果,antd 的样式正常,并且最上方的一个 a 标签并没有被 antd 所影响:
按需引入
方式 2:手动拼接 antd.less
全量
post-install 的方法多少显得有些 hack,另一种方法是手动拼出
antd/dist/antd.less
的文件依赖然后引入。结构与原本的引入相同,唯一不同的地方就是将 base.less 包裹了一层「作用域」,然后还需要在 webpack 的配置中添加 alias
然后在整个文件的入口引入
就好啦。
按需引入
很遗憾,在这种方式下,笔者折腾了半天也无法做到配合 babel-plugin-import 做按需引入。babel-plugin-import 提供了几种预置的样式加载方式及可定制化的方法,拿 Button 这个组件举例
antd/lib/button/index.css
,就是将 babel-plugin-import 配成这样:Button 这个组件没有问题,但是有些组件,比如
Col
是放在 Layout 这个目录的,按照组件名拼名字会找不到文件直接报错。还有,比如Input
这个组件是依赖Button
的样式的,只按需引Input
的样式是不行的,还要手动引入Button
的样式。antd/lib/button/css.js
,就是将 babel-plugin-import 配成这样:这个文件长这个样子
只需要把
require("../../style/index.less");
的这个引入干掉即可。但是遗憾的是,笔者试了IgnorePlugin
和alias
均无效。尤其是IgnorePlugin
,按照官方文档给的对 Moment.js 的处理方式,理论上应该可以忽略。但实际没有任何效果,如果哪位知道是为什么请告知。
总结
目前笔者所用的 antd 的版本还是 3.x,还没有升级到 v4 验证过,不过看了下 v4 的代码,base.less 还安安静静的躺在那里,目测使用方法是类似的。
这套方案在我们自己的业务上已经跑了几个月了,暂时没有发现什么问题。Ant Design 作为一套设计规范提供全局样式也是合理的,但还是希望官方可以提供一种可选的限定范围的全局样式,毕竟隔壁的 Material-UI 可是没这个问题(逃),默默许愿 antd v5 中可以解决!
彩(广)蛋(告)
之前为 antd 写了个 VS Code 生产力插件,自认为是最好用的 antd VS Code 插件了,欢迎 Star,Issue。
vscode-antd-rush
Ref