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

前言

提及換膚功能,前端確定不陌生,其實就是顏色值的更換,實現方式有不少,也各有優缺點javascript

 

1、看需求是什麼

通常來講換膚的需求分爲兩種:css

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

2. 另外一種是須要自定義色值,或者經過取色板取色,可供選擇的範圍就很大了前端

 

2、如何實現

 

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

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

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

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

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

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

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

但若是是有包含不一樣複雜背景圖片切換的時候,這種方式能夠實現,但其餘以下面要說的css變量 less modifyVars 就沒法實現了webpack

示例:git

<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類:github

  • 沒有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');

 

總結

一個看似簡單的需求能夠實現的方法有不少,具體怎麼實現要結合需求來動態進行選擇。

 

參考: 

http://www.javashuo.com/article/p-gyvwptgk-mq.html

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

相關文章
相關標籤/搜索