Vue3 + Vite + Ant Design Vue 暗黑模式切换方案:CSS变量与动态Less加载
在 Vue3 + Vite 项目中使用 Ant Design Vue 时,实现暗黑/亮色主题切换的核心思路是:抽离 CSS 变量,并动态替换框架自带 Less 文件。本文记录具体实现步骤和代码。一、全局 CSS 变量定义
在 src 下新建 vars.css 文件,声明一套基于 :root 的 CSS 变量,用于控制页面背景、文字颜色、边框色等。例如:
:root {
--page-bg-color: #fff;
--head-bg-color: rgba(255, 255, 255, 0.7);
--text-color: rgba(0, 0, 0, 0.85);
--line-color: #e8e8e8;
--content-bg-color: #f0f2f5;
}
二、准备两套入口 Less 文件
分别对应暗黑和亮色模式,放在 src/less 目录下。
light.less:
@import "../../node_modules/ant-design-vue/dist/antd.less";
@import "./index.css";
@import "./base.less";
@import "./vars.css";
dark.less:
@import "../../node_modules/ant-design-vue/dist/antd.dark.less";
@import "./index.css";
@import "./base.less";
@import "./vars.css";
其中 index.css 和 base.less 是项目自己的样式文件,可根据需要调整。关键是通过 @import 引入对应版本的 Ant Design 主题文件。
三、组件样式中使用 CSS 变量
在组件或页面 Less/CSS 中,用 CSS 变量替换固定色值。例如:
.pagemodal {
background: white; /* 降级方案 */
background: var(--page-bg-color);
border-radius: 5px;
padding: 10px;
}
这样当 --page-bg-color 变化时,组件样式自动跟随。
四、编写主题切换工具函数
创建 themeUtils.ts,封装两个核心方法。
1. changeTheme:动态创建 style 标签并注入 Less 编译后的 CSS 字符串(实际工程中 Less 文件经过 Vite 预处理后导出为 CSS 字符串)。
export const changeTheme = (theme: string) => {
const head = document.head;
document.getElementById("theme")?.remove(); // 移除旧主题样式
const styleDom = document.createElement("style");
styleDom.id = "theme";
styleDom.innerHTML = theme;
head.appendChild(styleDom);
};
2. changeCss:直接操作 body.style 的 setProperty 方法,更新 CSS 变量值。
export const changeCss = (css: string, value: string) => {
const body = document.body.style;
body.setProperty(css, value);
};
五、整合暗黑/亮色切换函数
先引入编译好的 Less 文件(Vite 默认支持将 .less 作为模块导入)。
import light from "../less/light.less";
import dark from "../less/dark.less";
export const DarkMode = (isDark: boolean) => {
if (isDark) {
changeTheme(dark);
changeCss("--page-bg-color", "#141414");
changeCss("--head-bg-color", "rgba(0, 0, 0, 0.5)");
changeCss("--line-color", "#2e2e2e");
changeCss("--content-bg-color", "rgb(255 255 255 / 4%)");
changeCss("--text-color", "rgba(255, 255, 255, 0.85)");
} else {
changeTheme(light);
changeCss("--page-bg-color", "white");
changeCss("--head-bg-color", "rgba(255, 255, 255, 0.7)");
changeCss("--line-color", "#e8e8e8");
changeCss("--content-bg-color", "#f0f2f5");
changeCss("--text-color", "rgba(0, 0, 0, 0.85)");
}
};
注意:导入 Less 文件时,Vite 会将它们编译为独立的 CSS 块,调用 changeTheme 时传入的是该 CSS 字符串。
六、调用示例
在应用入口或主题切换按钮中:
// 切换为暗黑模式
DarkMode(true);
// 恢复为亮色模式
DarkMode(false);
七、注意事项
- Vite 的 Less 导入需确保 less 和 less-loader 已安装,且配置正确。
- CSS 变量降级写法(如 background: white;)可兼容不支持 CSS 变量的旧浏览器,但现代项目一般无需。
- 如果多个组件都依赖这些变量,建议统一在 vars.css 中声明,并通过 import 引入。
- 此方案同时解决了 Ant Design Vue 组件内部样式的黑暗模式和自定义变量的同步切换。
总结:本方案将 Ant Design Vue 的暗黑主题与自定义 CSS 变量结合,通过动态替换 style 标签和更新 CSS 变量实现即时切换,代码干净且易于维护,适合 Vue3 + Vite 项目快速复用。
Re: Vue3 + Vite + Ant Design Vue 暗黑模式切换方案:CSS变量与动态Less加载
感谢分享这么完整的实现方案!用CSS变量配合动态Less加载确实是Vue3+Vite项目里切换Ant Design Vue主题比较灵活的做法,既保留了框架完整的主题变量,又能自定义全局颜色,维护起来也很清晰。特别喜欢你把两套Less入口文件分开组织,切换时用changeTheme整体替换框架样式,再用changeCss单独覆盖自定义CSS变量,这样职责非常明确。 一个小建议:在`DarkMode`函数里,`changeCss`每次都会调用多次setProperty,如果未来自定义CSS变量增多,可以考虑把不同主题的变量值抽成单独的对象,然后在函数里遍历设置,代码会更简洁一些。另外如果Less文件较大,动态创建style标签时可能需要注意一下加载性能,不过Vite编译后的CSS字符串应该不大,影响有限。 请问实际项目中你是用Vite的less插件直接导入.less文件吗?还是做了其他预处理?想了解一下这块在打包时的具体效果。再次感谢分享!Re: Vue3 + Vite + Ant Design Vue 暗黑模式切换方案:CSS变量与动态Less加载
这个方案很清晰,把CSS变量和动态加载Less结合起来,既照顾了Ant Design框架的主题切换,又让自定义样式跟着一起变。我之前也想过类似思路,但一直没处理好组件库的样式覆盖,学习到了。 想请教一下:在实际项目中import light from "../less/light.less",Vite会把它编译成CSS字符串,这个字符串直接放到内联style标签里,有没有遇到样式优先级的问题?比如插入了新的style标签后,会不会和之前已经加载的Ant Design样式冲突,导致一些样式需要额外增加权重?Re: Vue3 + Vite + Ant Design Vue 暗黑模式切换方案:CSS变量与动态Less加载
感谢分享这个方案,思路清晰,步骤也很完整。我之前也折腾过 Ant Design Vue 的主题切换,一直纠结于纯 CSS 变量能否完全覆盖框架内部的深层次样式。你通过动态替换完整的主题 Less 文件(light.less / dark.less)再加上 CSS 变量做自定义补丁,确实解决了框架样式跟随和自定义变量同步的问题,这个双重机制很实用。 一个小疑问:Vite 下直接 import Less 文件得到的是编译后的 CSS 字符串吗?我印象中 Vite 的 less 处理会输出独立的 CSS chunk,你在 changeTheme 里直接作为 innerHTML 插入 style 标签,会不会有作用域或优先级冲突?另外有没有考虑过在 DarkMode 函数里一次性设置所有 CSS 变量,而不是逐条调用 changeCss?比如准备一个对象循环设置,看起来会更简洁。 整体上学习了,有机会我也按这个结构重构一下项目里的主题切换,非常感谢!
页:
[1]