第10章: CSS变量和自定义属性
🎯 本章重点
- CSS变量声明和使用
- 作用域和继承机制
- JavaScript操作CSS变量
- 主题切换实现
- 响应式变量应用
- 性能优化技巧
📖 内容概述
10.1 CSS变量基础
10.1.1 变量声明和使用
:root {
--primary-color: #007bff;
--secondary-color: #6c757d;
--font-size-base: 16px;
--spacing-unit: 1rem;
--border-radius: 0.375rem;
--transition-duration: 0.3s;
}
.component {
--component-bg: #ffffff;
--component-padding: var(--spacing-unit);
--component-border: 1px solid #dee2e6;
}
.button {
background-color: var(--primary-color);
color: white;
padding: var(--spacing-unit);
border-radius: var(--border-radius);
transition: all var(--transition-duration);
}
.card {
background: var(--component-bg);
padding: var(--component-padding);
border: var(--component-border);
border-radius: calc(var(--border-radius) * 2);
}
10.1.2 变量命名规范
:root {
--color-primary: #007bff;
--color-secondary: #6c757d;
--color-success: #28a745;
--color-danger: #dc3545;
--color-warning: #ffc107;
--color-info: #17a2b8;
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 3rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.25rem;
--font-size-xl: 1.5rem;
--border-radius-sm: 0.2rem;
--border-radius: 0.375rem;
--border-radius-lg: 0.5rem;
--border-radius-xl: 1rem;
}
10.2 变量作用域和继承
10.2.1 作用域层级
:root {
--global-color: #333;
--global-size: 16px;
}
.component {
--component-color: #666;
--component-size: 14px;
color: var(--component-color);
font-size: var(--component-size);
}
.component .nested {
--nested-color: #999;
color: var(--nested-color);
background: var(--component-color);
font-size: var(--global-size);
}
@media (min-width: 768px) {
:root {
--spacing-unit: 1.5rem;
--font-size-base: 18px;
}
}
10.2.2 变量继承和覆盖
:root {
--text-color: #333;
--bg-color: #fff;
--accent-color: #007bff;
}
[data-theme="dark"] {
--text-color: #fff;
--bg-color: #333;
--accent-color: #66b3ff;
}
[data-theme="high-contrast"] {
--text-color: #000;
--bg-color: #ffff00;
--accent-color: #ff0000;
}
body {
color: var(--text-color);
background-color: var(--bg-color);
}
.button {
background-color: var(--accent-color);
color: var(--text-color);
}
10.3 JavaScript操作CSS变量
10.3.1 读取和设置变量
function getCssVariable(variableName) {
return getComputedStyle(document.documentElement)
.getPropertyValue(variableName)
.trim();
}
function setCssVariable(variableName, value) {
document.documentElement.style.setProperty(variableName, value);
}
function setCssVariables(variables) {
Object.entries(variables).forEach(([name, value]) => {
document.documentElement.style.setProperty(name, value);
});
}
const primaryColor = getCssVariable('--primary-color');
setCssVariable('--primary-color', '#ff0000');
setCssVariables({
'--primary-color': '#007bff',
'--secondary-color': '#6c757d',
'--spacing-unit': '1.5rem'
});
10.3.2 主题切换实现
class ThemeManager {
constructor() {
this.themes = {
light: {
'--bg-color': '#ffffff',
'--text-color': '#333333',
'--primary-color': '#007bff'
},
dark: {
'--bg-color': '#333333',
'--text-color': '#ffffff',
'--primary-color': '#66b3ff'
},
highContrast: {
'--bg-color': '#ffff00',
'--text-color': '#000000',
'--primary-color': '#ff0000'
}
};
this.currentTheme = this.getStoredTheme() || 'light';
this.applyTheme(this.currentTheme);
}
getStoredTheme() {
return localStorage.getItem('theme');
}
setStoredTheme(theme) {
localStorage.setItem('theme', theme);
}
applyTheme(themeName) {
const theme = this.themes[themeName];
if (!theme) return;
setCssVariables(theme);
this.currentTheme = themeName;
this.setStoredTheme(themeName);
document.documentElement.setAttribute('data-theme', themeName);
document.dispatchEvent(new CustomEvent('themeChange', {
detail: { theme: themeName }
}));
}
toggleTheme() {
const themes = Object.keys(this.themes);
const currentIndex = themes.indexOf(this.currentTheme);
const nextIndex = (currentIndex + 1) % themes.length;
this.applyTheme(themes[nextIndex]);
}
}
const themeManager = new ThemeManager();
document.getElementById('theme-toggle').addEventListener('click', () => {
themeManager.toggleTheme();
});
document.addEventListener('themeChange', (event) => {
console.log('Theme changed to:', event.detail.theme);
});
10.4 高级变量技巧
10.4.1 计算和数学运算
:root {
--base-size: 16px;
--spacing-multiplier: 1.5;
--header-height: 60px;
--footer-height: 40px;
}
.component {
font-size: calc(var(--base-size) * 1.125);
margin: calc(var(--base-size) * 2);
height: calc(100vh - var(--header-height) - var(--footer-height));
width: calc(50% - var(--base-size) * 2);
padding: calc(var(--base-size) * var(--spacing-multiplier));
}
@media (min-width: 768px) {
:root {
--base-size: 18px;
--spacing-multiplier: 2;
}
}
10.4.2 变量函数和回退值
.element {
color: var(--primary-color, blue);
background: var(--custom-bg, var(--fallback-bg, white));
border-color: var(
--border-color,
var(--primary-color,
var(--secondary-color, #ccc))
);
}
:root {
--hue: 210;
--saturation: 50%;
--lightness: 50%;
}
.dynamic-color {
background: hsl(
var(--hue),
var(--saturation),
var(--lightness)
);
border-color: hsl(
var(--hue),
var(--saturation),
calc(var(--lightness) - 20%)
);
}
10.5 响应式变量设计
10.5.1 断点变量系统
:root {
--breakpoint-sm: 576px;
--breakpoint-md: 768px;
--breakpoint-lg: 992px;
--breakpoint-xl: 1200px;
--breakpoint-xxl: 1400px;
}
:root {
--spacing-base: 1rem;
--spacing-sm: calc(var(--spacing-base) * 0.5);
--spacing-md: var(--spacing-base);
--spacing-lg: calc(var(--spacing-base) * 1.5);
}
@media (min-width: 768px) {
:root {
--spacing-base: 1.25rem;
}
}
@media (min-width: 1200px) {
:root {
--spacing-base: 1.5rem;
}
}
.container {
padding: var(--spacing-md);
}
@media (min-width: 768px) {
.container {
padding: var(--spacing-lg);
}
}
10.5.2 容器查询变量
.component {
container-type: inline-size;
container-name: component;
--columns: 1;
--gap: 1rem;
}
@container component (min-width: 300px) {
.component {
--columns: 2;
--gap: 1.5rem;
}
}
@container component (min-width: 600px) {
.component {
--columns: 3;
--gap: 2rem;
}
}
@container component (min-width: 900px) {
.component {
--columns: 4;
--gap: 2.5rem;
}
}
.grid {
display: grid;
grid-template-columns: repeat(var(--columns), 1fr);
gap: var(--gap);
}
10.6 性能优化和最佳实践
10.6.1 性能优化技巧
:root {
--color-primary: #007bff;
--color-primary-hover: #0056b3;
--color-primary-active: #004085;
--hue-primary: 210;
--saturation-primary: 100%;
--lightness-primary: 50%;
}
.optimized {
color: var(--color-primary);
margin: var(--spacing) 0;
transition: all 0.3s;
}
.critical {
color: #007bff;
color: var(--color-primary);
}
10.6.2 维护性最佳实践
:root {
--color-primary: #007bff;
--spacing-unit: 1rem;
}
:root {
--color-primary: #007bff;
--color-secondary: #6c757d;
--color-success: #28a745;
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.25rem;
}
@media (prefers-reduced-motion: reduce) {
:root {
--transition-duration: 0.01ms;
}
}
10.7 实战案例
10.7.1 设计系统实现
:root {
--color-primary-50: #e3f2fd;
--color-primary-100: #bbdefb;
--color-primary-500: #2196f3;
--color-primary-900: #0d47a1;
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 1rem;
--space-4: 1.5rem;
--space-5: 3rem;
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.button {
--button-bg: var(--color-primary-500);
--button-color: white;
--button-padding: var(--space-3) var(--space-4);
--button-border-radius: 0.375rem;
background: var(--button-bg);
color: var(--button-color);
padding: var(--button-padding);
border-radius: var(--button-border-radius);
}
.button--secondary {
--button-bg: var(--color-primary-100);
--button-color: var(--color-primary-900);
}
.button--large {
--button-padding: var(--space-4) var(--space-5);
}
💡 CSS变量总结
- 声明: 使用
--前缀声明变量
- 作用域: 支持全局和局部作用域
- 继承: 变量值可以继承和覆盖
- JavaScript: 可以通过JS动态操作
- 响应式: 支持媒体查询和容器查询
- 性能: 合理使用避免性能问题