前言
提及換膚功能,前端確定不陌生,其實就是顏色值的更換,實現方式有不少,也各有優缺點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
-
HTML 的 rel 屬性下的 alternate 實現: MDN Alternative style sheets
示例: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對象的disabled
值爲false
,可讓默認不渲染的CSS開始渲染。實現 demo
2. 對於制定動態色值換膚的實現
若是是要實現動態換膚,自定義色值,那上面的幾種方式就不適合了。
先看下已有的實現有哪些方法
Element-UI 有換膚功能 示例預覽
實現原理: 官方解釋
- 先把默認主題文件中涉及到顏色的 CSS 值替換成關鍵詞:https://github.com/ElementUI/theme-preview/blob/master/src/app.vue#L250-L274
- 根據用戶選擇的主題色生成一系列對應的顏色值:https://github.com/ElementUI/theme-preview/blob/master/src/utils/formula.json
- 把關鍵詞再換回剛剛生成的相應的顏色值:https://github.com/ElementUI/theme-preview/blob/master/src/utils/color.js
- 直接在頁面上加
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/