在了解方案前,我们多多少少应该见过这样类型的样式--primary-color
,这个是什么东东?其实它就是一个css变量
,也可叫css自定义属性,它是一种css规范,它一般定义在样式类里,如下
css
.theme{
--primary-color:grey;
}
那么问题来了,它有什么用?一般用来实现自定义主题,实时调整修改样式。既然知道了它的用处了,那么它应该如何用?这就需要var
:
css
background-color: var(--primary-color);
既然我们用过--primary-color这种规范,相信$primary-color应该也用过,它就是一个预处理器scss的变量,简称scss变量
,它与css变量区别是它不需要定义在样式类里,一般用来定义一个值而在多个地方使用
scss
$primary-color:grey;
:root{
--primary-color: $primary-color
}
那么问题来了,既然我们都初步了解了$var和--var,那么它们的区别究竟在哪里?
特性 | Sass 变量 ($var ) |
CSS 变量 (--var ) |
---|---|---|
编译时机 | 编译时处理 | 运行时处理 |
本质 | 在代码被编译成 CSS 之前 就被替换成对应的值。最终的 CSS 文件中不存在 $variable 。 |
是浏览器引擎能够识别的真实属性 。最终的 CSS 文件中保留着 var(--variable) 。 |
作用域 | 遵循 Sass 的代码作用域(文件、嵌套块)。 | 遵循 CSS 的级联和继承规则(DOM 结构)。 |
JavaScript 操作 | 无法通过 JS 访问或修改,编译后不存在了。 | 可以通过 JS 动态读取和修改。 |
能力 | 可以被用于选择器名、属性名、注释等(得益于编译过程)。 | 只能用作属性值。 |
兼容性 | 编译后变成普通 CSS,兼容所有浏览器。 | 现代浏览器支持良好(IE 基本不支持)。 |
我们可能疑问,上面两种变量跟主题有关系吗,当然有,如果不用它们,实现主题就不那么完美了,好了废话不多说,我们一起看例子
CSS类名切换
CSS类名切换:通过切换不同类名进行主题的切换
- 样式文件可以写在一个文件下,然后在根样式中引入
- 样式文件也可以写在多个不同主题文件下,然后全部根引入
css
.theme__default{ // 主题一
--primary-color:grey;
--text-color:#000;
}
.theme__blue{ // 主题二
--primary-color:blue;
--text-color:blue;
}
.theme__red{ // 主题三
--primary-color:red;
--text-color:red;
}
.bgc{
background-color: var(--primary-color);
}
.text{
color: var(--text-color);
}
通过声明对应的样式,然后再响应的html进行切换,切换内容如下
html
<el-select v-model="currentTheme" placeholder="Select" style="width: 180px">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<div class="mt-4" :class="`theme__${currentTheme}`">
<div class="bgc h-20 w-20"></div>
<p class="text">路灯下的光</p>
</div>
切换示例如下:

SCSS/SASS变量
SCSS/SASS变量:使用预处理器变量结合不同的类名生成多套样式
方式一:定义多个主题文件,通过scss的minxin语法定义主题样式
scss
/* theme-mixin.scss */
@mixin theme($name) {
.theme-#{$name} {
--bg-color: #{$bg-color};
--text-color: #{$text-color};
}
}
在每一个主题文件中引入并使用minxin函数进行相应的主题样式定义
scss
/* themes/light.scss */
$bg-color: #fff;
$text-color: #333;
@use "theme-mixin";
@include theme(light);
/* themes/dark.scss */
$bg-color: #121212;
$text-color: #fafafa;
@use "theme-mixin";
@include theme(dark);
在根样式中显式引入所有主题文件样式
scss
/* src/styles/index.scss */
@use "themes/light";
@use "themes/dark";
方式二:在同一个文件下定义样式变量,并用自定义属性data-theme实现主题样式定义
我们可能疑问data-theme是啥,其实它就是一个自定义属性,为html属性提供一个主题标识,原生html支持这种通过data-来定义标签内的属性。在使用这样的前提必须先定义一些主题映射,如下
scss
@use './variables/base-color.scss'; // 引入样式变量
// 定义主题映射
$themes: (
"light": (
primary-color: var(--oc-blue-6),
secondary-color: var(--oc-blue-0),
bg-color: var(--oc-white),
text-color: var(--oc-blue-5),
border-color: var(--oc-blue-5)
),
"dark": (
primary-color: var(oc-gray-9),
secondary-color: var(oc-gray-0),
bg-color: var(--oc-gray-6), // #1a1a1a
text-color: var(--oc-gray-4),
border-color: var(--oc-gray-5)
),
);
// 将SCSS变量转换为CSS变量
:root {
@each $theme, $map in $themes { // 遍历所有主题,$theme主题,$map键值对
&[data-theme="#{$theme}"] { // 属性选择器
@each $key, $value in $map { // 遍历当前主题的所有变量
--#{$key}: #{$value};
}
}
}
}
既然我们定义了theme那么在html中是如何使用的呢?
ts
document.documentElement.setAttribute('data-theme', theme);
关键就在于给documentElement设置data-theme属性
CSS-in-JS方案
安装一些插件,使其支持主题切换,以vue为例,我们需要安装pnpm i @vueuse/styles来支持主题,例如以下通过定义主题hooks,然后在全局的app.vue里引入并改变就可以实现主题
ts
// theme.ts
import { createGlobalState } from '@vueuse/core';
export const useTheme = createGlobalState(() => {
const isDark = ref(false);
const theme = computed(() =>
isDark.value
? {
'--primary': '#e74c3c',
'--bg': '#2c3e50',
'--text': '#ecf0f1',
}
: {
'--primary': '#3498db',
'--bg': '#ffffff',
'--text': '#333333',
}
);
return { isDark, theme };
});
第三方库实现
@vueuse/color-scheme(vue3)
ts
import { useColorMode } from '@vueuse/color-scheme'
const mode = useColorMode() // 'light' | 'dark' | 'auto'
mode.value = 'dark' // 自动同步到 <html class="dark">
vuetify
安装:
bash
npm i vuetify@next
在入口文件定义
ts
// main.ts
import { createVuetify } from 'vuetify'
const vuetify = createVuetify({
theme: {
themes: {
light: { colors: { primary: '#1976D2' } },
dark : { colors: { primary: '#BB86FC' } }
}
}
})
app.use(vuetify)
在需要变更的地方使用
ts
import { useTheme } from 'vuetify'
const theme = useTheme()
theme.global.name.value = 'dark'