使用 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/

相关文章
相关标签/搜索