antd select 下拉菜单的 style 属性_如何优雅地彻底解决 antd 全局样式问题
背景
由于某些原因,我們團隊負責在 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 插件,
將所有 .ant 開頭的類選擇器都同樣升高即可,利用的是 postcss-selector-parser 這個 PostCSS 官方提供的解析選擇器的庫,過濾出「第一個以 ant- 開頭的類選擇器」,在其前面添加一個屬性選擇器 [class*='ant-'],如果這個選擇器排在當前 rule 的第一個或者前面是一個 combinator,則再加一個通配符 *,這個同上面給 base.less 添加的選擇器,兩者同時提高相同權重既維持原有優(yōu)先級不變。
另外,如果某些元素雖然不在 antd 的組件里,但是也想走 antd 的全局樣式,只需在這些元素的最外層套一個 class className="ant-whatever",只要是 ant- 開頭的就可以。
這個 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。
步驟:
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 保持著瀏覽器原生的樣式按需引入
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 這個組件舉例
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.comRef
- “優(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 全局样式问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python多包运行_如何组织包含多个包
- 下一篇: 关于mysql和oracle错误的有_关