Skip to content

CSS 变量实战指南

CSS 变量(也称为自定义属性)是现代 CSS 的一个强大特性,它为我们提供了在 CSS 中使用变量的能力。与 Sass、Less 等预处理器变量不同,CSS 变量是原生的、动态的,可以在运行时修改。本文将深入探讨如何在大型项目中有效使用 CSS 变量。

目录

CSS 变量基础

什么是 CSS 变量?

CSS 变量是一种在 CSS 中存储值的方法,可以在整个文档中重复使用。它们使用 -- 前缀定义,通过 var() 函数使用。

css
/* 定义变量 */
:root {
  --primary-color: #3498db;
  --secondary-color: #2ecc71;
  --font-size-base: 16px;
  --spacing-unit: 8px;
}

/* 使用变量 */
.button {
  background-color: var(--primary-color);
  font-size: var(--font-size-base);
  padding: calc(var(--spacing-unit) * 2);
}

CSS 变量 vs 预处理器变量

特性CSS 变量Sass/Less 变量
运行时修改✅ 支持❌ 编译时确定
作用域✅ 支持❌ 全局作用域
浏览器支持✅ 现代浏览器✅ 编译后兼容
JavaScript 交互✅ 可直接操作❌ 需要重新编译
继承性✅ 支持继承❌ 不支持

变量命名规范

1. 语义化命名

css
/* ✅ 推荐:语义化命名 */
:root {
  /* 颜色系统 */
  --color-primary: #3498db;
  --color-secondary: #2ecc71;
  --color-success: #27ae60;
  --color-warning: #f39c12;
  --color-error: #e74c3c;
  --color-info: #3498db;
  
  /* 文本颜色 */
  --text-primary: #2c3e50;
  --text-secondary: #7f8c8d;
  --text-muted: #bdc3c7;
  --text-inverse: #ffffff;
  
  /* 背景颜色 */
  --bg-primary: #ffffff;
  --bg-secondary: #f8f9fa;
  --bg-dark: #2c3e50;
}

/* ❌ 避免:非语义化命名 */
:root {
  --blue: #3498db;
  --green: #2ecc71;
  --color1: #27ae60;
  --color2: #f39c12;
}

2. 分层命名系统

css
:root {
  /* 基础层:原子级变量 */
  --space-xs: 4px;
  --space-sm: 8px;
  --space-md: 16px;
  --space-lg: 24px;
  --space-xl: 32px;
  
  /* 组件层:组件特定变量 */
  --button-padding-y: var(--space-sm);
  --button-padding-x: var(--space-md);
  --button-border-radius: 4px;
  
  /* 布局层:页面级变量 */
  --header-height: 64px;
  --sidebar-width: 280px;
  --content-max-width: 1200px;
}

3. 响应式变量命名

css
:root {
  /* 移动端 */
  --font-size-h1: 24px;
  --container-padding: 16px;
  --grid-columns: 1;
}

@media (min-width: 768px) {
  :root {
    /* 平板端 */
    --font-size-h1: 32px;
    --container-padding: 24px;
    --grid-columns: 2;
  }
}

@media (min-width: 1024px) {
  :root {
    /* 桌面端 */
    --font-size-h1: 40px;
    --container-padding: 32px;
    --grid-columns: 3;
  }
}

作用域管理

1. 全局作用域

css
/* 全局变量定义在 :root */
:root {
  --global-primary-color: #3498db;
  --global-font-family: 'Helvetica Neue', Arial, sans-serif;
  --global-border-radius: 4px;
}

/* 全局变量可以在任何地方使用 */
.card {
  border-radius: var(--global-border-radius);
  font-family: var(--global-font-family);
}

2. 组件作用域

css
/* 组件级变量 */
.card {
  --card-bg: #ffffff;
  --card-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  --card-padding: 16px;
  
  background: var(--card-bg);
  box-shadow: var(--card-shadow);
  padding: var(--card-padding);
}

/* 组件变体 */
.card--dark {
  --card-bg: #2c3e50;
  --card-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}

.card--large {
  --card-padding: 24px;
}

3. 状态相关作用域

css
.button {
  --button-bg: var(--color-primary);
  --button-color: white;
  --button-scale: 1;
  
  background: var(--button-bg);
  color: var(--button-color);
  transform: scale(var(--button-scale));
  transition: all 0.2s ease;
}

.button:hover {
  --button-bg: var(--color-primary-dark);
  --button-scale: 1.05;
}

.button:active {
  --button-scale: 0.95;
}

.button:disabled {
  --button-bg: var(--color-disabled);
  --button-color: var(--text-muted);
  --button-scale: 1;
}

主题系统构建

1. 多主题支持

css
/* 基础主题变量 */
:root {
  --theme-primary: #3498db;
  --theme-secondary: #2ecc71;
  --theme-bg: #ffffff;
  --theme-text: #2c3e50;
  --theme-border: #e1e8ed;
}

/* 深色主题 */
[data-theme="dark"] {
  --theme-primary: #5dade2;
  --theme-secondary: #58d68d;
  --theme-bg: #1a1a1a;
  --theme-text: #ffffff;
  --theme-border: #333333;
}

/* 高对比度主题 */
[data-theme="high-contrast"] {
  --theme-primary: #000000;
  --theme-secondary: #000000;
  --theme-bg: #ffffff;
  --theme-text: #000000;
  --theme-border: #000000;
}

/* 使用主题变量 */
.app {
  background: var(--theme-bg);
  color: var(--theme-text);
  border-color: var(--theme-border);
}

2. JavaScript 主题切换

javascript
class ThemeManager {
  constructor() {
    this.currentTheme = localStorage.getItem('theme') || 'light';
    this.applyTheme(this.currentTheme);
  }
  
  applyTheme(theme) {
    document.documentElement.setAttribute('data-theme', theme);
    localStorage.setItem('theme', theme);
    this.currentTheme = theme;
    
    // 触发主题变更事件
    window.dispatchEvent(new CustomEvent('themechange', {
      detail: { theme }
    }));
  }
  
  toggleTheme() {
    const themes = ['light', 'dark', 'high-contrast'];
    const currentIndex = themes.indexOf(this.currentTheme);
    const nextIndex = (currentIndex + 1) % themes.length;
    this.applyTheme(themes[nextIndex]);
  }
  
  // 动态修改主题色
  setPrimaryColor(color) {
    document.documentElement.style.setProperty('--theme-primary', color);
  }
  
  // 获取当前主题变量值
  getThemeVariable(variable) {
    return getComputedStyle(document.documentElement)
      .getPropertyValue(`--theme-${variable}`);
  }
}

// 使用示例
const themeManager = new ThemeManager();

// 主题切换按钮
document.getElementById('theme-toggle').addEventListener('click', () => {
  themeManager.toggleTheme();
});

// 监听主题变更
window.addEventListener('themechange', (event) => {
  console.log('主题已切换到:', event.detail.theme);
});

3. 动态主题生成

javascript
// 基于主色生成完整主题
function generateTheme(primaryColor) {
  const hsl = hexToHsl(primaryColor);
  
  return {
    '--theme-primary': primaryColor,
    '--theme-primary-light': hslToHex(hsl.h, hsl.s, Math.min(hsl.l + 20, 100)),
    '--theme-primary-dark': hslToHex(hsl.h, hsl.s, Math.max(hsl.l - 20, 0)),
    '--theme-secondary': hslToHex((hsl.h + 120) % 360, hsl.s, hsl.l),
    '--theme-accent': hslToHex((hsl.h + 60) % 360, hsl.s, hsl.l)
  };
}

// 应用生成的主题
function applyGeneratedTheme(primaryColor) {
  const theme = generateTheme(primaryColor);
  
  Object.entries(theme).forEach(([property, value]) => {
    document.documentElement.style.setProperty(property, value);
  });
}

// 颜色转换工具函数
function hexToHsl(hex) {
  const r = parseInt(hex.slice(1, 3), 16) / 255;
  const g = parseInt(hex.slice(3, 5), 16) / 255;
  const b = parseInt(hex.slice(5, 7), 16) / 255;
  
  const max = Math.max(r, g, b);
  const min = Math.min(r, g, b);
  let h, s, l = (max + min) / 2;
  
  if (max === min) {
    h = s = 0;
  } else {
    const d = max - min;
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
    
    switch (max) {
      case r: h = (g - b) / d + (g < b ? 6 : 0); break;
      case g: h = (b - r) / d + 2; break;
      case b: h = (r - g) / d + 4; break;
    }
    h /= 6;
  }
  
  return { h: h * 360, s: s * 100, l: l * 100 };
}

function hslToHex(h, s, l) {
  l /= 100;
  const a = s * Math.min(l, 1 - l) / 100;
  const f = n => {
    const k = (n + h / 30) % 12;
    const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
    return Math.round(255 * color).toString(16).padStart(2, '0');
  };
  return `#${f(0)}${f(8)}${f(4)}`;
}

响应式设计中的应用

1. 响应式间距系统

css
:root {
  /* 基础间距单位 */
  --space-unit: 4px;
  
  /* 响应式间距 */
  --space-xs: calc(var(--space-unit) * 1); /* 4px */
  --space-sm: calc(var(--space-unit) * 2); /* 8px */
  --space-md: calc(var(--space-unit) * 4); /* 16px */
  --space-lg: calc(var(--space-unit) * 6); /* 24px */
  --space-xl: calc(var(--space-unit) * 8); /* 32px */
}

@media (min-width: 768px) {
  :root {
    --space-unit: 6px; /* 间距单位在大屏幕上增加 */
  }
}

@media (min-width: 1024px) {
  :root {
    --space-unit: 8px;
  }
}

/* 使用响应式间距 */
.container {
  padding: var(--space-md);
  margin-bottom: var(--space-lg);
}

.card {
  padding: var(--space-sm) var(--space-md);
  gap: var(--space-sm);
}

2. 响应式字体系统

css
:root {
  /* 基础字体大小 */
  --font-size-base: 16px;
  --font-scale: 1.2;
  
  /* 字体大小层级 */
  --font-size-xs: calc(var(--font-size-base) / var(--font-scale) / var(--font-scale));
  --font-size-sm: calc(var(--font-size-base) / var(--font-scale));
  --font-size-md: var(--font-size-base);
  --font-size-lg: calc(var(--font-size-base) * var(--font-scale));
  --font-size-xl: calc(var(--font-size-base) * var(--font-scale) * var(--font-scale));
  --font-size-2xl: calc(var(--font-size-base) * var(--font-scale) * var(--font-scale) * var(--font-scale));
}

@media (min-width: 768px) {
  :root {
    --font-size-base: 18px;
    --font-scale: 1.25;
  }
}

@media (min-width: 1024px) {
  :root {
    --font-size-base: 20px;
    --font-scale: 1.3;
  }
}

/* 使用响应式字体 */
h1 { font-size: var(--font-size-2xl); }
h2 { font-size: var(--font-size-xl); }
h3 { font-size: var(--font-size-lg); }
p { font-size: var(--font-size-md); }
small { font-size: var(--font-size-sm); }

3. 容器查询与 CSS 变量

css
/* 容器查询中使用 CSS 变量 */
.card-container {
  container-type: inline-size;
}

.card {
  --card-columns: 1;
  --card-gap: var(--space-sm);
  
  display: grid;
  grid-template-columns: repeat(var(--card-columns), 1fr);
  gap: var(--card-gap);
}

@container (min-width: 400px) {
  .card {
    --card-columns: 2;
    --card-gap: var(--space-md);
  }
}

@container (min-width: 600px) {
  .card {
    --card-columns: 3;
    --card-gap: var(--space-lg);
  }
}

与预处理器结合使用

1. Sass 与 CSS 变量结合

scss
// _variables.scss
:root {
  // 使用 Sass 变量生成 CSS 变量
  @each $name, $color in (
    'primary': #3498db,
    'secondary': #2ecc71,
    'success': #27ae60,
    'warning': #f39c12,
    'error': #e74c3c
  ) {
    --color-#{$name}: #{$color};
    --color-#{$name}-light: #{lighten($color, 20%)};
    --color-#{$name}-dark: #{darken($color, 20%)};
  }
}

// 生成间距变量
$spacing-values: (0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64);

:root {
  @each $value in $spacing-values {
    --space-#{$value}: #{$value}px;
  }
}

// 混合宏使用 CSS 变量
@mixin button-variant($color) {
  --button-bg: var(--color-#{$color});
  --button-bg-hover: var(--color-#{$color}-dark);
  --button-bg-active: var(--color-#{$color}-light);
  
  background: var(--button-bg);
  
  &:hover {
    background: var(--button-bg-hover);
  }
  
  &:active {
    background: var(--button-bg-active);
  }
}

// 使用混合宏
.btn-primary {
  @include button-variant('primary');
}

.btn-secondary {
  @include button-variant('secondary');
}

2. PostCSS 插件增强

javascript
// postcss.config.js
module.exports = {
  plugins: [
    // 自动添加 CSS 变量回退值
    require('postcss-custom-properties')({
      preserve: true, // 保留原始 CSS 变量
      fallback: true  // 添加回退值
    }),
    
    // CSS 变量优化
    require('postcss-css-variables')(),
    
    // 自动前缀
    require('autoprefixer')
  ]
};

// 输入
.button {
  color: var(--primary-color, #3498db);
}

// 输出
.button {
  color: #3498db; /* 回退值 */
  color: var(--primary-color, #3498db);
}

性能优化

1. 变量继承优化

css
/* ✅ 推荐:合理使用继承 */
:root {
  --base-font-size: 16px;
  --base-line-height: 1.5;
}

.text-content {
  --content-font-size: var(--base-font-size);
  --content-line-height: var(--base-line-height);
  
  font-size: var(--content-font-size);
  line-height: var(--content-line-height);
}

.text-content--large {
  --content-font-size: calc(var(--base-font-size) * 1.2);
}

/* ❌ 避免:过度嵌套 */
.deeply-nested {
  --level1: var(--base-value);
  --level2: var(--level1);
  --level3: var(--level2);
  --level4: var(--level3); /* 过度嵌套影响性能 */
}

2. 减少重复计算

css
/* ✅ 推荐:预计算复杂值 */
:root {
  --golden-ratio: 1.618;
  --base-size: 16px;
  
  /* 预计算常用值 */
  --size-sm: calc(var(--base-size) / var(--golden-ratio)); /* 9.89px */
  --size-md: var(--base-size); /* 16px */
  --size-lg: calc(var(--base-size) * var(--golden-ratio)); /* 25.89px */
  --size-xl: calc(var(--base-size) * var(--golden-ratio) * var(--golden-ratio)); /* 41.89px */
}

/* ❌ 避免:重复计算 */
.element1 {
  font-size: calc(16px * 1.618); /* 重复计算 */
}

.element2 {
  font-size: calc(16px * 1.618); /* 重复计算 */
}

3. 条件加载

css
/* 只在需要时加载复杂主题 */
@media (prefers-color-scheme: dark) {
  :root {
    --theme-bg: #1a1a1a;
    --theme-text: #ffffff;
  }
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --animation-duration: 0s;
    --transition-duration: 0s;
  }
}

@media (prefers-contrast: high) {
  :root {
    --border-width: 2px;
    --outline-width: 3px;
  }
}

调试和开发工具

1. CSS 变量调试

css
/* 调试模式:显示所有 CSS 变量 */
[data-debug="true"] {
  --debug-primary: var(--color-primary, 'undefined');
  --debug-secondary: var(--color-secondary, 'undefined');
  --debug-spacing: var(--space-md, 'undefined');
}

[data-debug="true"]::before {
  content: 
    'Primary: ' var(--debug-primary) '\A'
    'Secondary: ' var(--debug-secondary) '\A'
    'Spacing: ' var(--debug-spacing);
  white-space: pre;
  position: fixed;
  top: 10px;
  right: 10px;
  background: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 10px;
  font-family: monospace;
  font-size: 12px;
  z-index: 9999;
}

2. JavaScript 调试工具

javascript
// CSS 变量调试工具
class CSSVariableDebugger {
  constructor() {
    this.variables = new Map();
    this.collectVariables();
  }
  
  // 收集所有 CSS 变量
  collectVariables() {
    const styles = getComputedStyle(document.documentElement);
    
    for (let i = 0; i < styles.length; i++) {
      const property = styles[i];
      if (property.startsWith('--')) {
        const value = styles.getPropertyValue(property).trim();
        this.variables.set(property, value);
      }
    }
  }
  
  // 查找变量
  findVariable(pattern) {
    const regex = new RegExp(pattern, 'i');
    const matches = [];
    
    for (const [property, value] of this.variables) {
      if (regex.test(property) || regex.test(value)) {
        matches.push({ property, value });
      }
    }
    
    return matches;
  }
  
  // 显示所有变量
  showAll() {
    console.table(Array.from(this.variables.entries()).map(([property, value]) => ({
      Property: property,
      Value: value
    })));
  }
  
  // 监听变量变化
  watchVariable(property, callback) {
    const observer = new MutationObserver(() => {
      const newValue = getComputedStyle(document.documentElement)
        .getPropertyValue(property).trim();
      
      if (newValue !== this.variables.get(property)) {
        const oldValue = this.variables.get(property);
        this.variables.set(property, newValue);
        callback(property, newValue, oldValue);
      }
    });
    
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['style', 'data-theme']
    });
    
    return observer;
  }
}

// 使用调试工具
const debugger = new CSSVariableDebugger();

// 查找所有颜色相关变量
console.log('颜色变量:', debugger.findVariable('color'));

// 监听主题色变化
debugger.watchVariable('--theme-primary', (property, newValue, oldValue) => {
  console.log(`${property} 从 ${oldValue} 变更为 ${newValue}`);
});

3. 浏览器开发者工具技巧

javascript
// 在控制台中快速修改 CSS 变量
function setCSSVariable(property, value) {
  document.documentElement.style.setProperty(property, value);
  console.log(`设置 ${property} = ${value}`);
}

function getCSSVariable(property) {
  const value = getComputedStyle(document.documentElement)
    .getPropertyValue(property).trim();
  console.log(`${property} = ${value}`);
  return value;
}

// 批量设置变量
function setCSSVariables(variables) {
  Object.entries(variables).forEach(([property, value]) => {
    setCSSVariable(property, value);
  });
}

// 使用示例
setCSSVariable('--theme-primary', '#ff6b6b');
getCSSVariable('--theme-primary');

setCSSVariables({
  '--theme-primary': '#4ecdc4',
  '--theme-secondary': '#45b7d1',
  '--theme-accent': '#f9ca24'
});

实战案例

1. 设计系统实现

css
/* 设计系统基础变量 */
:root {
  /* 颜色系统 */
  --color-brand-50: #eff6ff;
  --color-brand-100: #dbeafe;
  --color-brand-200: #bfdbfe;
  --color-brand-300: #93c5fd;
  --color-brand-400: #60a5fa;
  --color-brand-500: #3b82f6;
  --color-brand-600: #2563eb;
  --color-brand-700: #1d4ed8;
  --color-brand-800: #1e40af;
  --color-brand-900: #1e3a8a;
  
  /* 语义化颜色 */
  --color-primary: var(--color-brand-600);
  --color-primary-hover: var(--color-brand-700);
  --color-primary-active: var(--color-brand-800);
  
  /* 字体系统 */
  --font-family-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-family-mono: 'Fira Code', Consolas, monospace;
  
  --font-weight-light: 300;
  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
  
  /* 间距系统 */
  --space-0: 0;
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;
  
  /* 阴影系统 */
  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
  --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
  
  /* 边框系统 */
  --border-width-0: 0;
  --border-width-1: 1px;
  --border-width-2: 2px;
  --border-width-4: 4px;
  
  --border-radius-none: 0;
  --border-radius-sm: 0.125rem;
  --border-radius-md: 0.375rem;
  --border-radius-lg: 0.5rem;
  --border-radius-xl: 0.75rem;
  --border-radius-full: 9999px;
}

/* 组件变量 */
.button {
  --button-padding-x: var(--space-4);
  --button-padding-y: var(--space-2);
  --button-font-size: var(--font-size-md);
  --button-font-weight: var(--font-weight-medium);
  --button-border-radius: var(--border-radius-md);
  --button-border-width: var(--border-width-1);
  
  padding: var(--button-padding-y) var(--button-padding-x);
  font-size: var(--button-font-size);
  font-weight: var(--button-font-weight);
  border-radius: var(--button-border-radius);
  border-width: var(--button-border-width);
}

.button--sm {
  --button-padding-x: var(--space-3);
  --button-padding-y: var(--space-1);
  --button-font-size: var(--font-size-sm);
}

.button--lg {
  --button-padding-x: var(--space-6);
  --button-padding-y: var(--space-3);
  --button-font-size: var(--font-size-lg);
}

2. 动态主题切换系统

javascript
// 完整的主题管理系统
class AdvancedThemeManager {
  constructor() {
    this.themes = new Map();
    this.currentTheme = 'light';
    this.customProperties = new Map();
    this.observers = [];
    
    this.init();
  }
  
  init() {
    // 注册默认主题
    this.registerTheme('light', {
      '--theme-bg': '#ffffff',
      '--theme-text': '#1a202c',
      '--theme-primary': '#3182ce',
      '--theme-secondary': '#38a169'
    });
    
    this.registerTheme('dark', {
      '--theme-bg': '#1a202c',
      '--theme-text': '#ffffff',
      '--theme-primary': '#63b3ed',
      '--theme-secondary': '#68d391'
    });
    
    // 从本地存储恢复主题
    const savedTheme = localStorage.getItem('theme');
    if (savedTheme && this.themes.has(savedTheme)) {
      this.applyTheme(savedTheme);
    }
    
    // 监听系统主题变化
    this.watchSystemTheme();
  }
  
  registerTheme(name, variables) {
    this.themes.set(name, variables);
  }
  
  applyTheme(themeName) {
    if (!this.themes.has(themeName)) {
      console.warn(`主题 "${themeName}" 不存在`);
      return;
    }
    
    const theme = this.themes.get(themeName);
    const root = document.documentElement;
    
    // 应用主题变量
    Object.entries(theme).forEach(([property, value]) => {
      root.style.setProperty(property, value);
    });
    
    // 应用自定义属性
    this.customProperties.forEach((value, property) => {
      root.style.setProperty(property, value);
    });
    
    this.currentTheme = themeName;
    localStorage.setItem('theme', themeName);
    
    // 通知观察者
    this.notifyObservers(themeName);
  }
  
  setCustomProperty(property, value) {
    this.customProperties.set(property, value);
    document.documentElement.style.setProperty(property, value);
  }
  
  getThemeVariable(variable) {
    return getComputedStyle(document.documentElement)
      .getPropertyValue(variable).trim();
  }
  
  watchSystemTheme() {
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    
    const handleChange = (e) => {
      if (this.currentTheme === 'auto') {
        this.applyTheme(e.matches ? 'dark' : 'light');
      }
    };
    
    mediaQuery.addEventListener('change', handleChange);
    
    // 注册 auto 主题
    this.registerTheme('auto', {});
  }
  
  subscribe(callback) {
    this.observers.push(callback);
    return () => {
      const index = this.observers.indexOf(callback);
      if (index > -1) {
        this.observers.splice(index, 1);
      }
    };
  }
  
  notifyObservers(theme) {
    this.observers.forEach(callback => callback(theme));
  }
  
  // 生成主题预览
  generateThemePreview(themeName) {
    if (!this.themes.has(themeName)) return null;
    
    const theme = this.themes.get(themeName);
    const preview = document.createElement('div');
    preview.className = 'theme-preview';
    
    preview.innerHTML = `
      <div class="theme-preview__colors">
        <div class="color-swatch" style="background: ${theme['--theme-primary']}"></div>
        <div class="color-swatch" style="background: ${theme['--theme-secondary']}"></div>
        <div class="color-swatch" style="background: ${theme['--theme-bg']}; border: 1px solid #ccc;"></div>
      </div>
      <div class="theme-preview__name">${themeName}</div>
    `;
    
    return preview;
  }
}

// 使用示例
const themeManager = new AdvancedThemeManager();

// 注册自定义主题
themeManager.registerTheme('ocean', {
  '--theme-bg': '#0f4c75',
  '--theme-text': '#ffffff',
  '--theme-primary': '#3282b8',
  '--theme-secondary': '#bbe1fa'
});

// 主题切换
document.getElementById('theme-select').addEventListener('change', (e) => {
  themeManager.applyTheme(e.target.value);
});

// 监听主题变化
themeManager.subscribe((theme) => {
  console.log(`主题已切换到: ${theme}`);
  document.body.className = `theme-${theme}`;
});

最佳实践总结

1. 命名约定

  • 使用语义化的变量名
  • 采用一致的命名前缀
  • 建立清晰的层级结构
  • 避免过于具体的命名

2. 性能考虑

  • 减少不必要的计算
  • 合理使用继承
  • 避免过度嵌套
  • 预计算常用值

3. 维护性

  • 建立完整的文档
  • 使用调试工具
  • 定期审查和重构
  • 保持向后兼容

4. 浏览器兼容性

  • 提供回退值
  • 使用 PostCSS 插件
  • 渐进增强策略
  • 特性检测

工具推荐

开发工具

  • CSS Variables Inspector:浏览器扩展,用于检查 CSS 变量
  • Stylus/Sass:预处理器增强
  • PostCSS:后处理优化
  • Design Tokens:设计令牌管理

在线工具

  • CSS Variables Generator:在线生成器
  • Color Palette Generator:颜色系统生成
  • Typography Scale Calculator:字体比例计算
  • Spacing System Generator:间距系统生成

总结

CSS 变量是现代前端开发的重要工具,它们提供了:

  1. 动态性:运行时修改样式的能力
  2. 可维护性:集中管理样式值
  3. 灵活性:支持复杂的主题系统
  4. 性能:减少重复代码和计算

通过合理使用 CSS 变量,我们可以构建更加灵活、可维护的样式系统,提升开发效率和用户体验。

记住,CSS 变量不是银弹,需要根据项目需求合理使用。在小型项目中,简单的 CSS 变量就足够了;在大型项目中,需要建立完整的设计系统和工具链支持。

参考资源

vitepress开发指南