使用 css/less 動態更換主題色(換膚功能)


前言

說起換膚功能,前端肯定不陌生,其實就是顏色值的更換,實現方式有很多,也各有優缺點

 

一、看需求是什么

一般來說換膚的需求分為兩種:

1. 一種是幾種可供選擇的顏色/主題樣式,進行選擇切換,這種可供選擇的主題切換不會很多

2. 另一種是需要自定義色值,或者通過取色板取色,可供選擇的范圍就很大了

 

二、如何實現

 

1. 對於可供選擇的顏色/主題樣式換膚的實現

  • 一個全局class控制樣式切換

  切換的時候js控制樣式的切換

  • JS改變href屬性值切換樣式表,例如:

<link id="skincolor" href="skin-default.css" rel="stylesheet" type="text/css">
document.getElementById('#skincolor').href = 'skin-red.css';

這種方式需要維護幾個主題樣式表,js點擊切換的時候通過改變css樣式表鏈接來實現。 例如這個 demo 

這種實現對於,顏色和主題多了的時候,維護起來就很麻煩,需要同時維護 n 個樣式文件,並且使用JS改變href屬性會帶來加載延遲,樣式切換不流暢,體驗也不好。

但如果是有包含不同復雜背景圖片切換的時候,這種方式可以實現,但其他如下面要說的css變量 less modifyVars 就無法實現了

示例:

<link href="reset.css" rel="stylesheet" type="text/css">
<link href="default.css" rel="stylesheet" type="text/css" title="Default Style">
<link href="fancy.css" rel="alternate stylesheet" type="text/css" title="Fancy">
<link href="basic.css" rel="alternate stylesheet" type="text/css" title="Basic">

所有樣式表都可分為3類:

  • 沒有title屬性,rel屬性值僅僅是stylesheet的<link>無論如何都會加載並渲染,如reset.css;
  • 有title屬性,rel屬性值僅僅是stylesheet的<link>作為默認樣式CSS文件加載並渲染,如default.css;
  • 有title屬性,rel屬性值同時包含alternate stylesheet的<link>作為備選樣式CSS文件加載,默認不渲染,如red.css和green.css;

alternate意味備用,相當於是 css 預加載進來備用,所以不會有上面那種切換延時

但怎么用呢?禁用掉?

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link 

link 的 disabled 屬性

 使用JavaScript代碼修改<link>元素DOM對象的disabledfalse,可以讓默認不渲染的CSS開始渲染。實現 demo

 

2. 對於制定動態色值換膚的實現

如果是要實現動態換膚,自定義色值,那上面的幾種方式就不適合了。 

先看下已有的實現有哪些方法

Element-UI 有換膚功能 示例預覽

實現原理:  官方解釋

  1. 先把默認主題文件中涉及到顏色的 CSS 值替換成關鍵詞:https://github.com/ElementUI/theme-preview/blob/master/src/app.vue#L250-L274
  2. 根據用戶選擇的主題色生成一系列對應的顏色值:https://github.com/ElementUI/theme-preview/blob/master/src/utils/formula.json
  3. 把關鍵詞再換回剛剛生成的相應的顏色值:https://github.com/ElementUI/theme-preview/blob/master/src/utils/color.js
  4. 直接在頁面上加 style 標簽,把生成的樣式填進去:https://github.com/ElementUI/theme-preview/blob/master/src/app.vue#L198-L211

看這個實現,還是比較麻煩的,想看看還有沒有更優雅的方法來實現

Ant Design 的更換主題色功能是用 less 提供的 modifyVars 的方式進行覆蓋變量來實現。

 

less的 modifyVars方法

modifyVars方法是是基於 less 在瀏覽器中的編譯來實現。所以在引入less文件的時候需要通過link方式引入,然后基於less.js中的方法來進行修改變量

less.modifyVars({
  '@themeColor': 'blue'
});

link方式引入主題色文件

<link rel="stylesheet/less" type="text/css" href="./src/less/public.less" />

更改主題色事件

// color 傳入顏色值
handleColorChange (color) {
    less.modifyVars({  // 調用 `less.modifyVars` 方法來改變變量值'
@themeColor':color }) .then(() => { console.log('修改成功'); }); };

如果發現項目運行報錯如下:

.bezierEasingMixin();
^
Inline JavaScript is not enabled. Is it set in your options?

 那可能是沒有開啟 javascriptEnabled:true

 在webpack配置里開啟

{
      test: /\.less$/,
      loader: 'less-loader',
      options: {
             javascriptEnabled: true
       }
},

less方法僅限於用less的項目才能使用,查了下sass是沒有類似 less.modifyVars 這種方法的。

 

那有沒有通用一點的方法呢?於是就有了

css 變量方法

如果項目里用的不是less, 那么還是用css的方法,通用且容易操作,使用css變量來進行主題色的修改,替換主題色變量,然后用setProperty來進行動態修改

用法就是給變量加--前綴,涉及到主題色的都改成var(--themeColor)這種方式

用之前看下兼容性

 https://caniuse.com/#search=CSS%20Variables

大部分主流瀏覽器還是支持的,而且主要是操作起來夠簡便。

用法舉例:

body{
   --themeColor:#000;
}

使用:

.main{
   color: var(--themeColor);
}

要修改主題色的話:

document.body.style.setProperty('--themeColor', '#ff0000');

 

總結

至此,總結了一些換膚的實現方案,大家如果有更好的方案,歡迎補充哦~

 

參考: 

https://juejin.im/post/5ca41617f265da3092006155

https://www.zhangxinxu.com/wordpress/2019/02/link-rel-alternate-website-skin/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM