前端主題切換方案 -react-antd-

本文作者爲 360 技術中臺數據平臺部的前端開發工程師

原文標題:前端主題切換方案

原文地址:https://juejin.cn/post/7117911005841063944

背景

最近有個需求,要給系統做個主題切換功能,網上關於主題的方案挺多,準備做一些調研,因爲項目是 react+antd 的一個後臺系統,開始從 antd 官方文檔中開始着手,做下整理對比,最後選一個最佳的方案用於實踐。

技術選型

less.modifyVars

antd 提供的一種主題切換方式,通過配置 webpack 的 less-loader,添加 modifyVars 對象,官方已經內置了一些主題變量,每次構建時更換對應色值即可實現主題切換。

// webpack.config.js
module.exports = {
  rules: [{
    test: /\.less$/,
    use: [{
      loader: 'style-loader',
    }{
      loader: 'css-loader', // translates CSS into CommonJS
    }{
      loader: 'less-loader', // compiles Less to CSS
+     options: {
+       lessOptions: { // 如果使用less-loader@5,請移除 lessOptions 這一級直接配置選項。
+         modifyVars: {
+           'primary-color''#1DA57A',
+           'link-color''#1DA57A',
+           'border-radius-base''2px',
+         },
+         javascriptEnabled: true,
+       },
+     },
    }],
    // ...other rules
  }],
  // ...other config
}

插入一個新的 Link 標籤,用新的 css 鏈接替換原來的樣式,這種方案實現上沒有難度,也沒有兼容問題,需要新建一套完全一樣的樣式類名,然後替換其中的色值,缺點是工作量太大,尤其開發中的項目來說,擴展性比較差,後期更換樣式類名,需要同步更改主題樣式文件:

theme2

CSS Variable

另外一個是用 ConfigProvider,需要注意在 antd@4.17.0-alpha.0 版本起才支持,而且 webpack 中如果使用了 babel-plugin-import,需要將其去除。本質是通過 CSS Variable(css 變量)實現,將顏色賦值變量,最大的問題是——有兼容性問題,在 IE 瀏覽器中不支持。補充:antd 好像對 CSS Variable 做了兼容處理。

項目內需要引入使用變量樣式文件:

-- import 'antd/dist/antd.min.css';
++ import 'antd/dist/antd.variable.min.css';

調用部分:

import { ConfigProvider } from 'antd';
 
ConfigProvider.config({
  theme: {
    primaryColor: '#25b864',
  },
});

css-vars-ponyfill

爲彌補 css variable 的不足,css-vars-ponyfill 做了一套兼容處理,原理大概是在 ie 等不支持 css var 的瀏覽器中將 var()中的變量值替換爲對應色值,在支持 css var 的瀏覽器中不做處理。另外是操作 dom,所以在 node 環境中無法使用。css-vars-ponyfill 主要暴露了一個 cssVar 方法,方法入參如下:

    export interface CSSVarsPonyfillOptions {
        rootElement?: Document|HTMLElement;
        shadowDOM?: boolean;
        include?: string;
        exclude?: string;
        variables?: {[key: string]: string};   // 顏色鍵值對
        onlyLegacy?: boolean;
        preserveStatic?: boolean;
        preserveVars?: boolean;
        silent?: boolean;
        updateDOM?: boolean;
        updateURLs?: boolean;
        watch?: null|boolean;
        onBeforeSend?(xhr: XMLHttpRequest, elm: HTMLLinkElement|HTMLStyleElement, url: string): void;
        onError?(message: string, elm: HTMLLinkElement|HTMLStyleElement, xhr: XMLHttpRequest, url: string): void;
        onWarning?(message: string): void;
        onSuccess?(cssText: string, elm: HTMLLinkElement|HTMLStyleElement, url: string): void;
        onComplete?(cssText: string, styleElms: HTMLStyleElement[], cssVariables: {[key: string]: string}, benchmark: number): void;
        onFinally?(hasChanged: boolean, hasNativeSupport: boolean, benchmark: number): void;
    }

主要的參數:variables:顏色鍵值對,切換主題即更換不同的 variables

技術對比

less.modifyVars 是靜態更改主題,適合定製化主題,構建完成之後不能再變;css 標籤的方法工作量太大,擴展性差;css variable 比較靈活,但有兼容問題,相對於 css 標籤方法,擴展性好點;css-vars-ponyfill 是 css variable 的優化版,解決了兼容問題,雖然會有服務端渲染的問題,如果項目是在瀏覽器 dom 環境下無傷大雅。

補充

做了一個簡單的 demo,分別用三種方式實現主題切換:css 標籤,css variable,css-vars-ponyfill。GitHub 地址:react-antd-theme

theme_link

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/PqCNaffGDXyflQkAaiQfVA