100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > antd select 下拉菜单的 style 属性_如何优雅地彻底解决 antd 全局样式问题

antd select 下拉菜单的 style 属性_如何优雅地彻底解决 antd 全局样式问题

时间:2024-02-13 08:30:04

相关推荐

antd select 下拉菜单的 style 属性_如何优雅地彻底解决 antd 全局样式问题

背景

由于某些原因,我们团队负责在 GitLab 上做二次开发,简单理解就是在 GitLab 上挂个 DOM 渲染用 React 写的一些组件,组件库选择了 antd,尴尬的是引入之后发现,GitLab 自身是带一套全局样式的,而 antd 又带了一套全局样式,导致 GitLab 的部分样式被覆盖,如图: a 标签颜色被 antd 覆盖:

checkbox 细微的样式错乱及大小改变:

注意看 checkbox 上侧的错位

原因

antd 的全局样式也不是一天两天的问题了,在社区中已经有很多讨论(#4331 #9363 #13459),但直到今天也没有进展。因为 Ant-Design 是一套设计语言,所以 antd 会引入一套 fork 自 normalize.css 的浏览器默认样式重置库。

引入全局样式的这个文件是 style/core/base.less,就是这个 base.less 会对各种元素的默认样式一顿格式化,截取一段:

...// remove inner border and padding from Firefox, but don't restore the outline like Normalize.button::-moz-focus-inner,[type='button']::-moz-focus-inner,[type='reset']::-moz-focus-inner,[type='submit']::-moz-focus-inner {padding: 0;border-style: none;}input[type='radio'],input[type='checkbox'] {box-sizing: border-box; // 1. Add the correct box sizing in IE 10-padding: 0; // 2. remove the padding in IE 10-}...

下图为 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 属性选择器即可达到目的。

流程如下:

第一步:将 antd 中的 base.less 替换为(具体怎么见「使用方式」)魔改的 base.less,这个魔改的 base.less 外面会套一层*[class*='ant-']限定其样式的「作用域」。这一步将全局样式限定在了所有有ant-的 class 的元素里。

*[class*='ant-'] {@import '~antd/lib/style/core/base.less';}

第二步:提高完了 base.less 的权重,再来提升组件的样式的权重,此举还能间接提升所有 antd 的样式的权重,避免外部的全局样式对 antd 造成侵入。

既然是改样式,那就用 CSS 界的 babel —— PostCSS,写个 PostCSS 插件,

/fi3ework/postcss-rename-selector​

将所有.ant开头的类选择器都同样升高即可,利用的是 postcss-selector-parser 这个 PostCSS 官方提供的解析选择器的库,过滤出「第一个以 ant- 开头的类选择器」,在其前面添加一个属性选择器[class*='ant-'],如果这个选择器排在当前 rule 的第一个或者前面是一个 combinator,则再加一个通配符*,这个同上面给 base.less 添加的选择器,两者同时提高相同权重既维持原有优先级不变。

另外,如果某些元素虽然不在 antd 的组件里,但是也想走 antd 的全局样式,只需在这些元素的最外层套一个 classclassName="ant-whatever",只要是ant-开头的就可以。

import parser, {Node } from 'postcss-selector-parser'import {SelectorReplace } from '../index'export function antdScopeReplacerFn(node: Node) {if (node.type !== 'selector') returnconst firstAntClassNodeIndex = node.nodes.findIndex((n) => {return n.type === 'class' && n.value.startsWith('ant-')})if (firstAntClassNodeIndex < 0) returnconst firstAntClassNode = node.nodes[firstAntClassNodeIndex]const prevNode = node.nodes[firstAntClassNodeIndex - 1]// preserve line breakconst spaces = {before: firstAntClassNode.rawSpaceBefore,after: firstAntClassNode.rawSpaceAfter,}firstAntClassNode.setPropertyWithoutEscape('rawSpaceBefore', '')const toInsert = []if (firstAntClassNodeIndex === 0 || prevNode.type === 'combinator') {const universal = parser.universal({value: '*',})toInsert.push(universal)}const attr = parser.attribute({attribute: 'class',operator: '*=',value: `"ant-"`,raws: {},})toInsert.push(attr)toInsert[0].spaces = spacesfirstAntClassNode.parent!.nodes.splice(firstAntClassNodeIndex, 0, ...toInsert)}export const antdReplacer: SelectorReplace = {type: 'each',replacer: antdScopeReplacerFn,}

这个 antd 的配置已经作为 preset 提供了,如果想使用直接引入即可

const {replacer, presets } = require('postcss-rename-selector')plugins: [replacer(presets.antdReplacer)]

效果如图:

使用方式

建了 demo 仓库,下面几种的方式在 demo 仓库中都可以找到:

/fi3ework/restricted-antd-style-demo​

方式 1:删除 base.less 一把梭

全量

思路是:在 post-install 阶段将antd/lib/style/core/index.less引入的@import base;这一行直接删掉,然后手动引入我们自己魔改的 base.less。

步骤:

写一个 post-install 脚本,直接改写antd/lib/style/core/index.less,这边已经有实现 /ant-design/ant-design/issues/9363#issuecomment-598091517PostCSS 中添加 postcss-rename-selector 插件并配置:

const {replacer, presets } = require('postcss-rename-selector')plugins: [replacer(presets.antdReplacer)]

3. 引入全量样式import 'antd/dist/antd.less'

4. 额外引入一个 base.less,限定在一个「作用域」下

@import '~antd/lib/style/mixins/index.less';*[class*='ant-'] {@import '~antd/lib/style/core/base.less';}

看下效果,antd 的样式正常,并且最上方的一个 a 标签并没有被 antd 所影响:

最上方的 normal link 保持着浏览器原生的样式

按需引入

同全量引入 1同全量引入 2配置 babel-plugin-import

['import',{libraryName: 'antd',style: true,},],

4. 同全量引入 4

方式 2:手动拼接 antd.less

全量

post-install 的方法多少显得有些 hack,另一种方法是手动拼出 `antd/dist/antd.less` 的文件依赖然后引入。

@import '~antd/lib/style/themes/index.less';@import '~antd/lib/style/mixins/index.less';*[class*='ant-'] {@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';

结构与原本的引入相同,唯一不同的地方就是将 base.less 包裹了一层「作用域」,然后还需要在 webpack 的配置中添加 alias

alias: {'antd/dist/antd.less$': path.resolve(__dirname, '../src/custom-dist.less')}

然后在整个文件的入口引入

import './custom-dist.less`

就好啦。

按需引入

很遗憾,在这种方式下,笔者折腾了半天也无法做到配合 babel-plugin-import 做按需引入。babel-plugin-import 提供了几种预置的样式加载方式及可定制化的方法,拿 Button 这个组件举例

antd/lib/button/index.css,就是将 babel-plugin-import 配成这样:

['import',{libraryName: 'antd',customStyleName: (name) => {return `antd/lib/${name}/style/index.css`}}],

Button 这个组件没有问题,但是有些组件,比如Col是放在 Layout 这个目录的,按照组件名拼名字会找不到文件直接报错。还有,比如Input这个组件是依赖Button的样式的,只按需引Input的样式是不行的,还要手动引入Button的样式。

2. 引antd/lib/button/css.js,就是将 babel-plugin-import 配成这样:

['import',{libraryName: 'antd',style: 'css'}],

这个文件长这个样子

'use strict'require('../../style/index.css')require('./index.css')

只需要把require("../../style/index.less");的这个引入干掉即可。但是遗憾的是,笔者试了IgnorePluginalias均无效。尤其是IgnorePlugin,按照官方文档给的对 Moment.js 的处理方式,理论上应该可以忽略。

new webpack.IgnorePlugin(/../../style/index.css/, /antd$/),

但实际没有任何效果,如果哪位知道是为什么请告知。

总结

目前笔者所用的 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

“优雅”的解决 Ant Design 全局样式问题/ant-design/ant-design/issues/4331/ant-design/ant-design/issues/9363/ant-design/ant-design/issues/13459

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。