浅析前端一键换肤5种方案:css样式覆盖、实现多套css主题、css自定义变量实现、webpack-theme-color-replacer插件实现自定义主题色、UI框架自定义主题功能
一、css 样式覆盖实现
1、核心:通过切换 CSS 选择器的方式实现主题样式的切换
- 在组件中保留不变的样式,将需要变化的样式进行抽离
- 提供多种样式,给不同的主题定义一个对应的 CSS 选择器
- 根据不同主题设置不同的样式
2、如何实现:
(1)通过 vuex
存储和控制全局的主题色;
(2)在 template
模板中通过 vuex
中的主题设置对应类名
(3)比如 theme.css
中通过 .light
和 .dark
两个类选择器来区分明亮主题和暗黑主题,并且事先准备了它们对应的样式
这种方式比较简单,就不多说。
3、缺点:
多种主题样式都要引入,代码量大;样式不易管理,需要改的话,几个主题样式里都需要改;样式不易查找,导致开发效率低等
二、实现多套 CSS 主题样式
1、核心:实现多套 CSS 主题样式,根据用户切换操作,通过 link
标签动态加载不同的主题样式,主要解决了多个主题色被编译到一个文件中导致单个文件过大的问题
PS:在很多给代码设置样式的时候,都可以见到这种不同主题样式的情景
2、实现:
(1)css 部分直接拆分成 ligth.css
和 dark.css
两个文件
(2)设置主题部分的 setTheme.js
代码如下
export default function setTheme(theme = 'ligth') {
let link = document.querySelector('#theme-link')
let href = "/theme/" + theme + ".css"
if (!link) {
let head = document.querySelector('head')
link = document.createElement('link')
link.id = '#theme-link'
link.rel = "stylesheet"
link.href = href
head.appendChild(link)
} else {
link.href = href
}
}
3、缺点:其实跟第一种差不多,与第一种方案相比,这种解决了多个主题色被编译到一个文件,导致文件过大问题。但是这种方式又没法把“变”与“不变”的样式分开,比如有些不需要主题色的样式,其实是“不变的”,应该不需要在每个 css 文件中都写一套的。
4、这样其实演化出进化版本:
(1)不变的 css 作为一个文件,如:common.css
(2)根据主题色变化的 css 作为多个主题色文件,如:light.css 和 dark.css
三、css 变量实现
// 无UI库依赖的主题切换
// 核心思想:css3 中的 :root 伪类选择器和 var 变量的应用
// 1、定义主题变量
:root {
--theme-color: #ccc;
}
// 2、使用主题变量
.test{
color: var(--theme-color);
}
// 3、动态改变主题
document.documentElement.style.setProperty('--theme-color', '#fff');
1、核心:通过 body.style.setProperty(key, value)
动态修改 body 上的 CSS 变量,使得页面上的其他部分可以应用最新的 CSS 变量对应的样式。
2、实现:
(1)比如 theme.css 中负责定义全局的 CSS 变量
/* 实现方式一 */
:root {
--theme-bg: initial; // 背景色
--theme-color: initial; // 字体色
--theme-boder-color: initial; // 边框色
}
/* 实现方式二 */
/* 默认值:light */
:root {
--theme-bg: #fff;
--theme-color: rgb(51, 50, 50);
--theme-img-bg: #fff;
--theme-boder-color: #d6d6d6;
}
/* 暗黑:dark */
[data-theme='dark'] {
--theme-bg: rgb(51, 50, 50);
--theme-color: #fff;
--theme-boder-color: #fff;
}
这里的实现方式一,就是通过 setProperty() 方法用于设置一个新的 CSS 属性,同时也可以修改 CSS 声明块中已存在的属性。
实现方式二,就是通过局部css变量覆盖全局css变量的原理
(2)比如 themeUtil.js 中负责获取当前对应样式值,以及设置 body 上的 CSS 变量值,如
const darkTheme = 'rgb(51, 50, 50)'
const lightTheme = '#fff'
const lightBorderTheme = '#d6d6d6'
// 获取对应的主题色值
export const getThemeMap = (isLight) => {
return { // 这里其实可以通过 key value 去设置多种主题的样式
'theme-bg': isLight ? lightTheme : darkTheme,
'theme-color': isLight ? darkTheme : lightTheme,
'theme-boder-color': isLight ? lightBorderTheme : lightTheme,
}
}
// 设置主题色值
export const setTheme = (isLight = true) => {
const themeMap = getThemeMap(isLight)
const body = document.body
/* 实现方式一 */ 设置全局的css变量
Object.keys(themeMap).forEach(key => {
body.style.setProperty(`--${key}`, themeMap[key])
})
/* 实现方式二 */ 设置局部的css变量,局部的会覆盖全局的变量
// body.setAttribute('data-theme', isLight ? 'light' : 'dark')
}
(3)通过 var()
在组件中应用对应 CSS 变量,比如在头部中的使用:color: var(--theme-color);
3、缺点:兼容性不好
4、优化:可通过 css-vars-ponyfill
对 CSS 变量进行兼容处理
四、webpack-theme-color-replacer插件实现自定义主题色
以上方案都是我们需要事先知道有哪些主题色方案,但是,如果主题不固定的,怎么办呢?
也有方案实现:可借用webpack插件:webpack-theme-color-replacer 来实现,但我没具体用过,想了解的搜一下吧,网上挺多介绍如何做的。
五、UI 框架自定义主题功能
比如 ElementUI 的自定义主题,具体见官方文档:https://element.eleme.cn/#/zh-CN/component/custom-theme
Ant-design-vue 定制主题,具体见官方文档:https://www.antdv.com/docs/vue/customize-theme-cn/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2018-04-20 vue中watch的用法总结以及报错处理Error in callback for watcher "checkList"
2018-04-20 CSS渐变字体、镂空字体、input框提示信息颜色、给图片加上内阴影、3/4圆
2018-04-20 ES6 import 引用文件夹/目录及其处理过程
2018-04-20 Nginx部署前端代码实现前后端分离及Nginx gzip参数详解
2018-04-20 windows往linux里拷贝内容编码问题导致nginx报错:unknown directive “ “ in /etc/nginx/conf.d/XXX.conf 的问题