日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時間:2025/5/22 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 antd select 下拉菜单的 style 属性_如何优雅地彻底解决 antd 全局样式问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

背景

由于某些原因,我們團隊負責在 GitLab 上做二次開發(fā),簡單理解就是在 GitLab 上掛個 DOM 渲染用 React 寫的一些組件,組件庫選擇了 antd,尷尬的是引入之后發(fā)現(xiàn),GitLab 自身是帶一套全局樣式的,而 antd 又帶了一套全局樣式,導致 GitLab 的部分樣式被覆蓋,如圖: a 標簽顏色被 antd 覆蓋:

checkbox 細微的樣式錯亂及大小改變:

注意看 checkbox 上側的錯位

原因

antd 的全局樣式也不是一天兩天的問題了,在社區(qū)中已經有很多討論(#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 的全局樣式),我們需要達到的目的可以進一步變?yōu)?「收斂 base.less,并保證外部的全局樣式無法輕易覆蓋 antd 的樣式」。

簡單限定 base.less

之前社區(qū)中出現(xiàn)過將 base.less 外面套一層 .ant-container 的方案,但一個顯著的缺陷就是提高了 base.less 中樣式的權重導致樣式錯位。

全面提高 ant- 的優(yōu)先級

但是限定 base.less 這個思路是沒有錯的,base.less 需要被套一層「作用域」,那再給所有已有的 antd 組件提高權重保證原有的選擇器優(yōu)先級不變就好了。

幸運的是,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 插件,

https://github.com/fi3ework/postcss-rename-selector?github.com

將所有 .ant 開頭的類選擇器都同樣升高即可,利用的是 postcss-selector-parser 這個 PostCSS 官方提供的解析選擇器的庫,過濾出「第一個以 ant- 開頭的類選擇器」,在其前面添加一個屬性選擇器 [class*='ant-'],如果這個選擇器排在當前 rule 的第一個或者前面是一個 combinator,則再加一個通配符 *,這個同上面給 base.less 添加的選擇器,兩者同時提高相同權重既維持原有優(yōu)先級不變。
另外,如果某些元素雖然不在 antd 的組件里,但是也想走 antd 的全局樣式,只需在這些元素的最外層套一個 class className="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 倉庫中都可以找到:

https://github.com/fi3ework/restricted-antd-style-demo?github.com

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

全量

思路是:在 post-install 階段將 antd/lib/style/core/index.less 引入的 @import base; 這一行直接刪掉,然后手動引入我們自己魔改的 base.less。

步驟:

  • 寫一個 post-install 腳本,直接改寫 antd/lib/style/core/index.less,這邊已經有實現(xiàn) https://github.com/ant-design/ant-design/issues/9363#issuecomment-598091517
  • PostCSS 中添加 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"); 的這個引入干掉即可。但是遺憾的是,筆者試了 IgnorePlugin 和 alias 均無效。尤其是 IgnorePlugin,按照官方文檔給的對 Moment.js 的處理方式,理論上應該可以忽略。

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

    但實際沒有任何效果,如果哪位知道是為什么請告知。

    總結

    目前筆者所用的 antd 的版本還是 3.x,還沒有升級到 v4 驗證過,不過看了下 v4 的代碼,base.less 還安安靜靜的躺在那里,目測使用方法是類似的。

    這套方案在我們自己的業(yè)務上已經跑了幾個月了,暫時沒有發(fā)現(xiàn)什么問題。Ant Design 作為一套設計規(guī)范提供全局樣式也是合理的,但還是希望官方可以提供一種可選的限定范圍的全局樣式,畢竟隔壁的 Material-UI 可是沒這個問題(逃),默默許愿 antd v5 中可以解決!

    彩蛋(廣告)

    之前為 antd 寫了個 VS Code 生產力插件,自認為是最好用的 antd VS Code 插件了(逃),歡迎 Star,Issue。

    vscode-antd-rush?github.com

    Ref

    • “優(yōu)雅”的解決 Ant Design 全局樣式問題
    • https://github.com/ant-design/ant-design/issues/4331
    • https://github.com/ant-design/ant-design/issues/9363
    • https://github.com/ant-design/ant-design/issues/13459

    總結

    以上是生活随笔為你收集整理的antd select 下拉菜单的 style 属性_如何优雅地彻底解决 antd 全局样式问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。