阿里數(shù)據(jù)的umi + antd動(dòng)態(tài)主題實(shí)踐

隨著嵌入阿里數(shù)據(jù)頁面的需求增多珊佣,出現(xiàn)了一些要求較高的業(yè)務(wù)方蹋宦,希望能指定阿里數(shù)據(jù)的主題色,來和他們的品牌色保持一致咒锻,讓產(chǎn)品有更好的體驗(yàn)冷冗。于是我們開始了動(dòng)態(tài)主題功能的調(diào)研,本來以為是個(gè)比較簡(jiǎn)單的事情惑艇,實(shí)際還是有遇到一些曲折的蒿辙,不過最終效果挺滿意的拇泛,符合我們的需求,同時(shí)很簡(jiǎn)單思灌、很輕量俺叭。

一、現(xiàn)有方案

動(dòng)手之前先調(diào)研了一波可選的方案泰偿,現(xiàn)有方案大致是兩類:一類是編譯構(gòu)建的時(shí)候就有多份預(yù)設(shè)主題熄守,在運(yùn)行時(shí)只做樣式切換,新增一類主題需重新構(gòu)建發(fā)布耗跛;另一類是運(yùn)行時(shí)可指定任意主題裕照,新增一類主題幾乎沒有成本,很方便拓展调塌。

1牍氛、編譯多份預(yù)設(shè)主題

Class切換

編譯出的CSS示例如下,通過給body設(shè)置theme-lighttheme-darkclass來切換主題烟阐。借助Less/Sass的能力可以較方便批量處理,但弊端也很明顯紊扬,CSS文件大小會(huì)倍增蜒茄。

// index.css
.theme-light div {
    color: #000;
}

.theme-dark div {
    color: #fff;
}

構(gòu)建多份CSS

對(duì)于class切換方案的弊端,我們可以通過構(gòu)建多份css文件來解決餐屎,比如我們的less代碼如下:

div {
    color: @primary-color;
}

然后構(gòu)建階段指定@primary-color為不同色值檀葛,來得到多份css產(chǎn)物:

// index-light.css
.div {
    color: #000;
}
// index-dark.css
div {
    color: #fff;
}

在運(yùn)行期間,通過切換加載index-light.cssindex-dark.css腹缩,來達(dá)到切換主題的效果屿聋。但這個(gè)方案也不友好,需要侵入構(gòu)建配置藏鹊,然后構(gòu)建耗時(shí)會(huì)增加润讥。

在編譯階段預(yù)置多份主題的方案,實(shí)現(xiàn)還算簡(jiǎn)單盘寡,原理也很好理解楚殿,但都有存在明顯的弊端,且拓展新主題會(huì)有成本竿痰。

2脆粥、運(yùn)行時(shí)指定任意主題

如果要低成本拓展主題,就必須借助運(yùn)行時(shí)的能力了影涉,實(shí)現(xiàn)復(fù)雜度由難到易变隔,大致有下面三種方案:

CSS模板+運(yùn)行時(shí)替換

這類方案需要先準(zhǔn)備一個(gè)css模板文件,然后根據(jù)用戶指定的顏色值注入到模板里去蟹倾,動(dòng)態(tài)產(chǎn)出最終的css文件匣缘,Element-ui便是使用了這個(gè)方案,在切換顏色時(shí),會(huì)把色值作為參數(shù)傳給后端來得到新的css文件:

Element-ui動(dòng)態(tài)主題.png

當(dāng)然這個(gè)工作純前端也可以做孵户,方案還是挺不錯(cuò)的萧朝。

Less變量

這個(gè)方案借助less.js的運(yùn)行時(shí)能力,來實(shí)現(xiàn)類似上面方案的效果夏哭,css模板在這里成了less文件检柬,運(yùn)行時(shí)替換由less.jsmodifyVars提供,我們的編碼工作量變少了竖配。使用大概是這樣:

  • html主文檔增加項(xiàng)目的less文件和less.js
<link rel="stylesheet/less" type="text/css" href="/styles.less" />
<script src="https://cdn.jsdelivr.net/npm/less@4.1.1"></script>
  • 使用modifyVars修改顏色變量
window.less.modifyVars({
  '@primary-color': '#0035ff'
})

該方案的弊端不少何址,一是要引入40kb的less.js運(yùn)行時(shí);二是對(duì)編碼和打包一定侵入进胯,我們需要把所有l(wèi)ess文件加到html中用爪;三是主題切換不會(huì)很流暢,因?yàn)?code>modifyVars后涉及到less文件的重新編譯胁镐。

CSS變量

CSS變量是CSS3標(biāo)準(zhǔn)的新功能偎血,通過它做主題很簡(jiǎn)單,比如下面是我們的樣式:

div {
    // 使用--primary-color變量的顏色盯漂,無值則用默認(rèn)的#000
    color: var(--primary-color, #000); 
}

切換主題時(shí)颇玷,只需通過document的API設(shè)置新的顏色值即可

document.body.style.setProperty('--primary-color', '#fff')

感覺這個(gè)方案是上述所有方案里最簡(jiǎn)單的,功能強(qiáng)大也很好理解就缆。

此外也有類似類似styled-components的css in js方案帖渠,但對(duì)項(xiàng)目改動(dòng)太大了,且指定antd組件的主題會(huì)很麻煩竭宰,可以直接忽略空郊。

二、我們的選擇

編譯多份預(yù)設(shè)主題類型的方案首先被我們拍死了切揭,我們對(duì)低成本拓展的要求比較高狞甚,否則業(yè)務(wù)方如果換主題色,我們還得跟著發(fā)版...

運(yùn)行時(shí)指定任意主題的方案里廓旬,功能上都能滿足我們的需求入愧,其中CSS變量方案成本最低,且:

  • 主流瀏覽器都已支持嗤谚,然后我們產(chǎn)品的用戶99%+都是chrome棺蛛,兼容性可以不考慮;
  • 然后我們本身已經(jīng)使用了less巩步,通過把@primary: #ff6a00改成@primary: var(--primary-color, #ff6a00)可以很方便使用旁赊,不需要大量改動(dòng)項(xiàng)目中已有的less文件;
  • 我們發(fā)現(xiàn)antd也已經(jīng)支持了CSS變量動(dòng)態(tài)指定主題椅野;

完美终畅,所以我們最終選擇了CSS變量方案籍胯。

三、動(dòng)手實(shí)踐

1离福、修改global.less

把寫死的less變量的值杖狼,改成CSS變量的方式,原先的值放入默認(rèn)值

- @primary: #ff6a00;
- @primary5: #ff6a000d;
- @primary15: #ff6a0026;
- @primary75: #ff6a00BF;

+ @primary: var(--primary-color, #ff6a00);
+ @primary5: var(--primary-color-5, #ff6a000d);
+ @primary15: var(--primary-color-15, #ff6a0026);
+ @primary75: var(--primary-color-75, #ff6a00BF);

本地跑一下妖爷,沒啥問題蝶涩,顏色都正常

2、修改CSS變量

我們新增了一個(gè)theme.ts文件絮识,在入口會(huì)執(zhí)行它的setupTheme來使用URL參數(shù)上指定的主題色绿聘。

// theme.ts
import { getUrlParams } from '@/utils/utils';

export let primaryColor = '#ff6a00';
export let primaryColor5 = '#ff6a000d';
export let primaryColor15 = '#ff6a0026';
export let primaryColor75 = '#ff6a00BF';

export function setupTheme() {
  const params = getUrlParams() as any;
  if (params?.primaryColor) {
    primaryColor = `#${params?.primaryColor.toLocaleLowerCase()}`;
    primaryColor5 = `${primaryColor}0d`;
    primaryColor15 = `${primaryColor}25`;
    primaryColor75 = `${primaryColor}BF`;
  }
  document.body.style?.setProperty('--primary-color', primaryColor);
  document.body.style?.setProperty('--primary-color-5', primaryColor5);
  document.body.style?.setProperty('--primary-color-15', primaryColor15);
  document.body.style?.setProperty('--primary-color-75', primaryColor75);
}

本地跑一下,指定primaryColor參數(shù)為其它色值次舌,除了antd系列組件都已經(jīng)生效了

3熄攘、指定antd組件主題

跟著文檔指引,我們升級(jí)了antd4.17.1-alpha.1版本彼念,importantd/dist/antd.variable.min.css挪圾,然后在theme.ts里新增了ConfigProvider來設(shè)置主題色,刷新下頁面逐沙,antd系列組件也生效了哲思,完美!打包發(fā)到預(yù)發(fā)感受下...

發(fā)到預(yù)發(fā)后問題來了酱吝,antd只有部分組件主題生效了,有些組件如分頁器沒生效土思,調(diào)試發(fā)現(xiàn)antd樣式有冗余务热,部分組件的CSS變量版樣式被覆蓋了,我們的umi.css大概是這樣:

// CSS變量版的樣式在前己儒,被后面的覆蓋了崎岂,導(dǎo)致指定的主題色沒生效
.ant-pagination-item-active {
        border-color: var(--ant-primary-color);
}

.ant-pagination-item-active {
        border-color: #ff6a00;
}

我的第一反應(yīng)是修改下CSS順序,讓CSS變量版的樣式在后闪湾,折騰了一番發(fā)現(xiàn)不行冲甘,發(fā)現(xiàn)webpack打包后的CSS順序不和import順序一致,最后看到這個(gè)issue就決定放棄了途样,webpack成員表示他們不能保證這個(gè)順序江醇。

4、關(guān)閉antd的按需加載

antd的文檔所寫何暇,antd動(dòng)態(tài)主題需要關(guān)閉按需加載:

注:如果你使用了 babel-plugin-import陶夜,需要將其去除。

看來只能這樣了裆站,從umi文檔得知条辟,@umijs/plugin-antd會(huì)對(duì)antd做按需引入黔夭,翻了下源碼目前無法配置關(guān)閉,我們于是提了個(gè)PR羽嫡,釘釘私聊了期賢本姥,期賢了解了背景后很快合并了PR并發(fā)了新版本,非常贊杭棵。

接著我們升級(jí)了@umijs/preset-react婚惫,在.umirc.ts里新增了disableBabelPluginImport配置禁用了按需加載,可喜的是打包后的產(chǎn)物竟然還有一些減少颜屠,看來大量使用antd組件時(shí)沒必要開啟按需加載...

antd: {
   disableBabelPluginImport: true
}

應(yīng)該穩(wěn)了辰妙,發(fā)到預(yù)發(fā)再感受一下...

分頁器是好了,但按鈕的居然壞了甫窟,一調(diào)試發(fā)現(xiàn)還是因?yàn)槿哂鄻邮矫芑耄珻SS變量樣式被覆蓋導(dǎo)致,最終定位到是@ant-design/pro-layout引入的

5粗井、指定pro-layout主題

原因是pro-layou有引用lib|es 目錄下的 less 文件尔破,按antd文檔所說,需要在less中注入@root-entry-name: variable變量浇衬,在.umirc.ts中配置如下:

theme: {
   'root-entry-name': 'variable'
}

再次發(fā)到預(yù)發(fā)懒构,OK,全妥了耘擂!

注意在theme里配置了'root-entry-name': 'variable'后胆剧,不能再配置'primary-color'的值

四、總結(jié)

可以看到醉冤,基于CSS變量的動(dòng)態(tài)主題方案還是比較簡(jiǎn)單的秩霍,對(duì)于已經(jīng)使用less的項(xiàng)目,接入成本很低蚁阳,方案輕量好拓展铃绒,并且antd也已經(jīng)給了官方支持,進(jìn)一步降低了使用成本螺捐,相信以后會(huì)成為更多人的選擇颠悬。

拓展閱讀:
CSS 變量教程:https://www.ruanyifeng.com/blog/2017/05/css-variables.html
Element-ui換膚方案:https://github.com/ElemeFE/element/issues/3054
聊一聊前端換膚:https://segmentfault.com/a/1190000018593994

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市定血,隨后出現(xiàn)的幾起案子赔癌,更是在濱河造成了極大的恐慌,老刑警劉巖澜沟,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件届榄,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡倔喂,警方通過查閱死者的電腦和手機(jī)铝条,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門靖苇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人班缰,你說我怎么就攤上這事贤壁。” “怎么了埠忘?”我有些...
    開封第一講書人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵脾拆,是天一觀的道長。 經(jīng)常有香客問我莹妒,道長名船,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任旨怠,我火速辦了婚禮渠驼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鉴腻。我一直安慰自己迷扇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開白布爽哎。 她就那樣靜靜地躺著蜓席,像睡著了一般。 火紅的嫁衣襯著肌膚如雪课锌。 梳的紋絲不亂的頭發(fā)上厨内,一...
    開封第一講書人閱讀 49,806評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音渺贤,去河邊找鬼雏胃。 笑死,一個(gè)胖子當(dāng)著我的面吹牛癣亚,可吹牛的內(nèi)容都是我干的丑掺。 我是一名探鬼主播获印,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼述雾,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了兼丰?” 一聲冷哼從身側(cè)響起玻孟,我...
    開封第一講書人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鳍征,沒想到半個(gè)月后黍翎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡艳丛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年匣掸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了趟紊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡碰酝,死狀恐怖霎匈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情送爸,我是刑警寧澤铛嘱,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站袭厂,受9級(jí)特大地震影響墨吓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜纹磺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一帖烘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爽航,春花似錦蚓让、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至衷佃,卻和暖如春趟卸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背氏义。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來泰國打工锄列, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人惯悠。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓邻邮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親克婶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子筒严,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容