前端主题切换方案实践
前言
主题切换方案大致可以分为两种方案:
- 固定主题
- 用户自定义主题
固定主题即系统提供固定的几种主题颜色供用户选择,这种方案一般主题不会太多。
用户自定义主题即系统允许用户可以自定义主题颜色,如通过取色面板设定主题颜色。
一、加载指定主题css文件
这种方案一般适合固定几种主题的切换,根据不同主题开发对应主题的css文件。当切换主题时加载对应的css文件。
可以将页面的通用样式定义在一个文件,比如不涉及颜色的width、height、font-size等。然后将涉及到颜色相关的样式属性如color、background等写在对应主题文件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 公共样式文件 -->
<link rel="stylesheet" href="./css/common.css">
<!-- 默认主题 -->
<link rel="stylesheet" href="./css/light.css" data-theme="light">
</head>
<body>
<h3>主题方案:加载不同css文件</h3>
<p>
<button id="switch">切换主题</button>
</p>
<div class="wrp"></div>
</body>
</html>
/* dark */
.wrp{
background-color: #666;
color:blueviolet;
}
/* light */
.wrp{
background-color: red;
color: #Fff
}
<script>
window.onload = function(){
//默认主题
let theme = 'light';
const switchBtn = document.getElementById('switch')
const wrp = document.getElementsByClassName('wrp')[0]
wrp.innerHTML = theme
// 加载主题样式文件
function loadTheme(theme){
const linkTag = document.createElement('link');
linkTag.setAttribute('rel', 'stylesheet')
linkTag.setAttribute('data-theme', theme)
linkTag.setAttribute('href', `./css/${theme}.css`)
document.getElementsByTagName('head')[0].appendChild(linkTag)
wrp.innerHTML = theme
}
// 绑定事件
switchBtn.addEventListener('click', function(){
// 主题切换
theme = theme === 'light' ? 'dark' : 'light';
const link = document.getElementsByTagName('link')
const arrLink = [...link]
arrLink.forEach(item => {
const nowTheme = item.getAttribute('data-theme')
if(nowTheme && nowTheme !== theme){
// 删除旧主题
item.parentElement.removeChild(item)
// 加载新主题
loadTheme(theme)
}
})
}, false)
}
</script>
特点:
此方案比较简单,但是在开发阶段会比较繁琐,需要维护不同主题颜色文件。由于需要加载对应主题样式文件,所以在切换主题时候可能会存在延迟。
二、css3 自定义属性
自定义属性是css3提供的新特性,自定义属性以两个减号(--)声明,由var()函数来取值。
/* 声明自定义属性 */
body{
--default-width: 100px;
}
/* 访问自定义属性 */
.wrp{
width: var(--default-width)
}
作用域:
自定义属性所在的容器下的节点均可访问。
方案介绍:
- 在文档根元素伪类(:root)下定义主题相关的主题颜色值。
- 通过html5原属自定义属性(data-)来声明不同主题。
- 在用户选择对应主题时候修改根元素自定义属性值。
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./index.css">
<script src="./index.js"></script>
</head>
<body>
<h3>css自定义属性实现页面主题切换</h3>
<p>dark/light: <input type="checkbox" id="checkbox" value="dark"></p>
<div class="content">这是一段描述文字</div>
</body>
</html>
window.onload = function(){
// 设置自定义属性值
function switchRootTheme(theme){
const htmlElement = document.getElementsByTagName('html')[0];
const targetTheme = htmlElement.getAttribute('data-theme');
if(theme !== targetTheme){
htmlElement.setAttribute('data-theme', theme)
}
}
// 切换固定主题
const chekboxS = document.getElementById('checkbox');
chekboxS.addEventListener('click', function(e){
if(e.target.checked) {
// dark
switchRootTheme('dark')
} else {
// light
switchRootTheme('light')
}
}, false)
}
html[data-theme='dark']:root {
--primary-color: red;
}
html[data-theme='light']:root{
--primary-color: #666;
}
.content{
width: 80%;
height: 220px;
margin: 0 auto;
text-align: center;
background-color: var(--primary-color);
}
特点
- 此方案不需要维护不同主题样式文件
- 此方案不需要在切换主题时候请求加载对应样式文件而存在延迟
- 存在一定的兼容性问题,ie11不兼容。
三、自定义主题颜色
此方案与前面两种方案不同,不再是仅仅支持固定的几种主题颜色,而是允许用户随意设定主题颜色。通过取色面板可以快速的切换主题颜色。
这种方案是在第二种方案的基础上升级而来。结合css自定义属性,通过js获取和设置自定义属性值从而实现自定义切换主题方案。
- 获取:element.style.getPropertyValue(自定义属性名)或者getComputedStyle(element).getPropertyValue(自定义属性名)
- 设置:element.style.setProperty(自定义属性名,值)
在方案二的基础上增加以下代码:
<h3>动态主题</h3>
<p>选择主题颜色:<input type="color" id="customColor"></p>
// 动态随机主题
const customColor = document.getElementById('customColor')
customColor.addEventListener('change', function(e){
const selectValue = e.target.value;
const htmlElement = document.getElementsByTagName('html')[0];
// 获取自定义变量值
console.log(getComputedStyle(htmlElement).getPropertyValue('--primary-color'))
// 设置自定义变量值
htmlElement.style.setProperty('--primary-color', selectValue)
}, false)
总结
除了上面的三种方案之外,其实还有很多方案可以实现,如css优先级覆盖、less/scss变量、html{filter:grayscale(1)}。如有不对之处,欢迎交流学习。
转载自:https://juejin.cn/post/7236290319391703098