普通视图

发现新文章,点击刷新页面。
昨天 — 2025年8月23日首页

用scss设计一下系统主题有什么方案吗

2025年8月23日 23:16

在了解方案前,我们多多少少应该见过这样类型的样式--primary-color,这个是什么东东?其实它就是一个css变量,也可叫css自定义属性,它是一种css规范,它一般定义在样式类里,如下

.theme{
  --primary-color:grey;
}

那么问题来了,它有什么用?一般用来实现自定义主题,实时调整修改样式。既然知道了它的用处了,那么它应该如何用?这就需要var


background-color: var(--primary-color);

既然我们用过--primary-color这种规范,相信$primary-color应该也用过,它就是一个预处理器scss的变量,简称scss变量,它与css变量区别是它不需要定义在样式类里,一般用来定义一个值而在多个地方使用

$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类名切换:通过切换不同类名进行主题的切换

  • 样式文件可以写在一个文件下,然后在根样式中引入
  • 样式文件也可以写在多个不同主题文件下,然后全部根引入
.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进行切换,切换内容如下

<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>

切换示例如下:

2025082301.gif

SCSS/SASS变量

SCSS/SASS变量:使用预处理器变量结合不同的类名生成多套样式

方式一:定义多个主题文件,通过scss的minxin语法定义主题样式

/* theme-mixin.scss */
@mixin theme($name) {
  .theme-#{$name} {
    --bg-color: #{$bg-color};
    --text-color: #{$text-color};

  }
}

在每一个主题文件中引入并使用minxin函数进行相应的主题样式定义

/* 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);

在根样式中显式引入所有主题文件样式

/* src/styles/index.scss */
@use "themes/light";
@use "themes/dark";

方式二:在同一个文件下定义样式变量,并用自定义属性data-theme实现主题样式定义

我们可能疑问data-theme是啥,其实它就是一个自定义属性,为html属性提供一个主题标识,原生html支持这种通过data-来定义标签内的属性。在使用这样的前提必须先定义一些主题映射,如下

@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中是如何使用的呢?

 document.documentElement.setAttribute('data-theme', theme);

关键就在于给documentElement设置data-theme属性

CSS-in-JS方案

安装一些插件,使其支持主题切换,以vue为例,我们需要安装pnpm i @vueuse/styles来支持主题,例如以下通过定义主题hooks,然后在全局的app.vue里引入并改变就可以实现主题

// 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)

import { useColorMode } from '@vueuse/color-scheme'
const mode = useColorMode()  // 'light' | 'dark' | 'auto'
mode.value = 'dark'          // 自动同步到 <html class="dark">

vuetify

安装:

npm i vuetify@next

在入口文件定义

// main.ts
import { createVuetify } from 'vuetify'

const vuetify = createVuetify({
  theme: {
    themes: {
      light: { colors: { primary: '#1976D2' } },
      dark : { colors: { primary: '#BB86FC' } }
    }
  }
})
app.use(vuetify)

在需要变更的地方使用

import { useTheme } from 'vuetify'
const theme = useTheme()
theme.global.name.value = 'dark'
❌
❌