前端换肤的解决方案
这是五种均为通用方案,可以适用于各种前端框架,脚手架中
# 一、 利用class 命名空间
这是最简单的换肤方式, 看下面示例即可轻松理解。
- 利用class 名称准备两个主题:
p.red-theme {
color: red;
}
p.blue-theme {
color: blue;
}
1
2
3
4
5
6
7
2
3
4
5
6
7
- 如果用红色主题, 给body增加 red-theme标签
<body class="red-theme"> <p> 这里是红色主题 </p> ... </body>
1
- 如果用蓝色主题, 用 blue-theme 代替 red-theme
<body class="blue-theme"> <p> 这里是蓝色主题 </p> ... </body>
1
# 优缺点
- 优点: 简单,好理解,好实现
- 缺点: CSS中需多写主题的class,代码容易混乱;需手动编写
# 参考
基于element动态换肤 (opens new window)
# 二、 准备多套CSS主题
本地存放多套主题, 根据需要切换加载不同的样式
- 准备一份默认样式主题
/*theme-default.css*/
p { color: #333 }
1
2
2
- 准备各主题的样式
/* theme-red.css */
p { color: red }
1
2
2
/* theme-blue.css */
p { color: blue }
1
2
2
- 页面加载后,根据用户需求加载不同的样式列表
var link = document.createElement('link');
link.type = 'text/css';
link.id = "theme-blue";
link.rel = 'stylesheet';
link.href = '/css/theme-blue.css';
document.getElementsByTagName("head")[0].appendChild(link);
1
2
3
4
5
6
2
3
4
5
6
- 有时候需要保存用户使用的主题,可以通过如下方式:
- 利用路由标记
- 利用cookie标记
- 利用localstorage
- 保存到后端服务器
# 优缺点
- 优点: 简单,好理解,好实现
- 缺点: 需要手写两份以上CSS配色样式; 切换样式需要下载CSS的时间
# 参考
web网页中主题切换的实现思路 (opens new window) 中有更多细节
# 三、 利用CSS预处理生成多套主题样式
这是“准备多套CSS主题”的优化方案,利用CSS预处理生成多套主题样式,再根据需要切换
- 利用Less,stylus 或 sass 的变量代替颜色值
- 配置多个主题颜色配置
- 利用webpack等工具输出多套主题样式
- 页面加载后,根据用户需求加载不同的样式列表(同方案2)
# 优缺点
- 优点: 不用手写两套CSS
- 确定: 配置复杂;生成冗余的CSS文件; 切换样式需要下载CSS的时间
# 参考
webpack的配置比较复杂,可以看这篇文章:webpack 换肤功能多主题/配色样式打包解决方案 (opens new window)
ant 环境下可以利用antd-theme-generator 快速配置,详见:antd-theme-generator (opens new window),antd在线换肤定制功能 (opens new window)
# 四、 动态换肤
这是element ui中的换肤方案,支持浏览器热换肤。生成一套主题, 将主题配色配置写在js中,在浏览器中用js动态修改style标签覆盖原有的CSS。
- 准备一套默认theme.css样式
/* theme.css */
.title { color: #FF0000 }
1
2
2
- 准备主题色配置
var colors = {
red: { themeColor: "#FF0000" },
blue: { themeColor: "#0000FF" },
};
1
2
3
4
2
3
4
- 异步获取
theme.css
,将颜色值替换为关键词
关键字可以确保以后能多次换色
var styles = ''
axios.get('theme.css').then((resp=> {
const colorMap = {
'#FF0000': 'themeColor'
}
styles = resp.data
Object.keys(colorMap).forEach(key => {
const value = colorMap[key]
styles = styles.replace(new RegExp(key, 'ig'), value)
})
}))
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
style 变为:
.title { color: theme-color }
1
- 把关键词再换回刚刚生成的相应的颜色值,并在页面上添加 style 标签
// console 中执行 writeNewStyle (styles, colors.blue) 即可变色
function writeNewStyle (originalStyle, colors) {
let oldEl = document.getElementById('temp-style')
let cssText = originalStyle
// 替换颜色值
Object.keys(colors).forEach(key => {
cssText = cssText.replace(new RegExp(key, 'ig'), colors[key])
})
const style = document.createElement('style')
style.innerText = cssText
style.id = 'temp-style'
oldEl ? document.head.replaceChild(style, oldEl) :
document.head.appendChild(style) // 将style写入页面
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
此时style 变为:
.title { color: '#0000FF' }
1
# 优缺点
- 优点: 只需一套CSS文件; 换肤不需要延迟等候;可自动适配多种主题色;
- 缺点: 稍难理解; 需准确的css颜色值;可能受限于浏览器性能;
# 参考
本文最后有该方案的完整代码
Vue 换肤实践 (opens new window)
elementUI 及 vuetifyjs动态换色实践 (opens new window)
vue-element-admin 动态换肤 (opens new window)
webpack 插件抽取CSS中的主题色 (opens new window)
# 五、 CSS 变量换肤
利用CSS 变量设置颜色, 用js动态修改CSS变量,进而换色。
如果不考虑IE兼容,这是最佳换肤方案
看下面的例子,很好理解
<html>
<head>
<title>CSS varies</title>
<style>
:root {
--theme-color: red /* css 变量赋值位置 */
}
.title {
color: var(--theme-color) /* 用css变量标记颜色 */
}
</style>
</head>
<body>
<h3 class="title">CSS 变量换肤</h3>
<script>
// console 中执行 changceColor('blue') 即可变色
function changeColor(color = 'blue') {
document.documentElement.style.setProperty("--theme-color",color);
}
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 优缺点
- 优点:只需一套CSS文件; 换肤不需要延迟等候;对浏览器性能要求低;可自动适配多种主题色;
- 缺点: 不支持IE, 2016年前的chrome,safari; 兼容性参见Can I Use CSS Variables (opens new window)
# 参考
# 参考文章链接
← 每日一题集合