使用Tailwindcss和css变量实现换肤

2,817 阅读3分钟

使用vite + Tailwindcss搭建基础框架

git仓库地址快速访问项目

目前比较常见的换肤方式

  • 编写多套css文件(一套主题一套样式),通过动态修改link标签的href来实现换肤
  • 通过css变量来实现换肤,通过配置css变量,增加class调用不同css变量实现换肤

创建vite项目

// 使用NPM方式
npm init vite@latest
// 默认选择vue + ts版本

初始化Tailwind CSS

  • 安装Tailwind依赖
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
  • 生成tailwind.config.js
npx tailwindcss init -p
// 执行命令之后 会生成最小化的tailwind.config.js
// tailwind.config.js
module.exports = {
  purge: [], // 在生产环境去除没有用到的css变量
  darkMode: false, // or 'media' or 'class' 是否开启暗黑模式 默认不开启
  theme: {// 主题配置
    extend: {// 主题扩展配置 比如增加color或者自定义color
    },
  },
  variants: {
    extend: {},
  },
  plugins: [],
}
  • 创建主样式文件 index.scss,定义主题变量
// index.scss
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
  // 默认主题色蓝色
  :root {
    // 背景色
    --color-bg-base: 191, 219, 254;
    // 卡片颜色
    --color-bg-card: 147, 197, 253;
    // 按钮颜色
    --color-bg-btn: 96, 165, 250;
    // 按钮hover颜色
    --color-bg-btn-hover: 59, 130, 246;
    // 字体颜色
    --color-text-base: #3B82F6;
    // 按钮字体颜色
    --color-btn-base: #fff;
  }
  .theme-pink {
    // 背景色
    --color-bg-base: 251, 207, 232;
    // 卡片颜色
    --color-bg-card: 249, 168, 212;
    // 按钮颜色
    --color-bg-btn: 244, 114, 182;
    // 按钮hover颜色
    --color-bg-btn-hover: 236, 72, 153;
    // 字体颜色
    --color-text-base: #EC4899;
    // 按钮字体颜色
    --color-btn-base: #fff;
  }
  .theme-dark {
    // 背景色
    --color-bg-base: 17, 24, 39;
    // 卡片颜色
    --color-bg-card: 55, 65, 81;
    // 按钮颜色
    --color-bg-btn: 75, 85, 99;
    // 按钮hover颜色
    --color-bg-btn-hover: 107, 114, 128;
    // 字体颜色
    --color-text-base: #fff;
    // 按钮字体颜色
    --color-btn-base: #fff;
  }
}

@layer components {
  .s-btn { // 按钮的基础样式
    @apply bg-skin-btn hover:bg-skin-btn-hover px-4 py-2 rounded;
  }
  .s-card { // 卡片的基础样式
    @apply bg-skin-card rounded-2xl p-8 min-w-max min-h-max flex flex-col items-center;
  }
}
  • 修改tailwind.config.js中的配置
/** @type {import('tailwindcss').Config} */
// 该方法是为了颜色基础类可以提供设置透明度的快捷方式,
function withOpacityValue(variable) {
  // 返回一个函数,透明度为可选参数,这样在 HTML 元素中使用颜色基础类时,既可以采用 text-blue-500 方式,也支持 text-blue-500/20 快捷同时设置透明度的形式
  return ({ opacityValue }) => {
    if (opacityValue === undefined) {
      return `rgb(var(${variable}))`;
    }
    return `rgba(var(${variable}), ${opacityValue})`;
  };
}

module.exports = {
  darkMode: 'class', // media跟随系统颜色, class:允许用户主动切换
  content: [
    './index.html',
    './src/**/*.{vue,js,ts,tsx,jsx}'
  ],
  theme: {
    extend: {
      backgroundColor: { // 此处用来定义主题的背景色基础样式
        skin: {
          bg: withOpacityValue('--color-bg-base'),
          card: withOpacityValue('--color-bg-card'),
          btn: withOpacityValue('--color-bg-btn'),
          'btn-hover': withOpacityValue('--color-bg-btn-hover'),
        }
      },
      textColor: { // 文本的基础样式
        'primary': 'var(--color-text-base)',
        'btn-base': 'var(--color-btn-base)',
      }
    },
  },
  plugins: [],
}
  • 在main.ts中引入
import { createApp } from 'vue'
import './index.scss'
import App from './App.vue'

createApp(App).mount('#app')
  • 创建Theme.vue组件
<template>
  <!--背景颜色-->
  <div class="transition-all bg-skin-bg h-screen flex justify-center items-center">
    <!--卡片颜色-->
    <div class="s-card">
      <h1 class="text-3xl font-extrabold text-primary">尝试定制你的主题</h1>
      <h2 class="text-lg my-3 text-amber-50">使用Tailwindcss和css变量实现换肤</h2>
      <div class="w-full flex justify-evenly space-x-2">
        <button class="s-btn text-btn-base" @click="changeTheme()">蓝色主题</button>
        <button class="s-btn text-btn-base" @click="changeTheme(THEME_LIST[0])">粉色主题</button>
        <button class="s-btn text-btn-base" @click="changeTheme(THEME_LIST[1])">黑色主题</button>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
  const THEME_LIST = ['theme-pink', 'theme-dark']
  const changeTheme = function(theme: string = '') {
    const classList = document.documentElement.classList
    THEME_LIST.forEach(item => document.documentElement.classList.remove(item))
    if (theme) {
      classList.add(theme)
    }
  }
</script>
<style>
</style>
  • 在APP.vue中引入Theme组件
<script setup lang="ts">
import Theme from './components/Theme.vue'
</script>

<template>
  <Theme />
</template>
  • 效果如下
  • 默认主题色

image.png

  • 粉色主题

image.png

  • 黑色主题

image.png