CSS 变量教程

1. CSS 变量概述

CSS 变量(也称为自定义属性)是 CSS3 中引入的一项强大功能,它允许你定义可重用的值,并在整个样式表中引用这些值。使用 CSS 变量可以使你的代码更加简洁、可维护,并且可以实现一些以前需要 JavaScript 才能实现的动态样式效果。

在本教程中,我们将探讨 CSS 变量的基本用法和高级特性,以及如何在实际项目中有效地使用它们。

2. 核心知识点

2.1 变量定义和使用

CSS 变量通过 -- 前缀定义,使用 var() 函数引用。

/* 定义变量 */
:root {
    --primary-color: #3498db;
    --secondary-color: #2ecc71;
    --font-size: 16px;
    --spacing: 10px;
    --border-radius: 4px;
}

/* 使用变量 */
.element {
    color: var(--primary-color);
    font-size: var(--font-size);
    margin: var(--spacing);
    border-radius: var(--border-radius);
}

/* 使用变量并提供默认值 */
.another-element {
    color: var(--primary-color, blue); /* 如果 --primary-color 未定义,使用 blue */
    background-color: var(--accent-color, #f1c40f); /* 如果 --accent-color 未定义,使用 #f1c40f */
}

2.2 变量作用域

CSS 变量的作用域由定义它们的选择器决定。在 :root 伪类中定义的变量是全局变量,可以在整个文档中使用。在其他选择器中定义的变量是局部变量,只能在该选择器及其子元素中使用。

/* 全局变量 */
:root {
    --global-color: #3498db;
}

/* 局部变量 */
.container {
    --local-color: #2ecc71;
    color: var(--local-color); /* 可以使用局部变量 */
    border-color: var(--global-color); /* 可以使用全局变量 */
}

.child {
    color: var(--local-color); /* 可以继承父元素的局部变量 */
}

.sibling {
    color: var(--local-color); /* 不能使用其他元素的局部变量,会使用默认值 */
}

2.3 变量继承

CSS 变量会从父元素继承,这意味着子元素可以使用父元素中定义的变量。

.parent {
    --parent-color: #3498db;
    color: var(--parent-color);
}

.child {
    /* 继承父元素的变量 */
    border-color: var(--parent-color);
}

.grandchild {
    /* 继承父元素的变量,间接继承祖父元素的变量 */
    background-color: var(--parent-color);
}

2.4 动态修改变量

CSS 变量可以通过 JavaScript 动态修改,这使得它们非常适合用于主题切换、响应式设计等场景。

// 获取根元素
const root = document.documentElement;

// 设置变量值
root.style.setProperty('--primary-color', '#e74c3c');

// 获取变量值
const primaryColor = getComputedStyle(root).getPropertyValue('--primary-color');
console.log(primaryColor); // 输出: #e74c3c

// 切换主题
function setTheme(theme) {
    if (theme === 'light') {
        root.style.setProperty('--background-color', '#ffffff');
        root.style.setProperty('--text-color', '#333333');
        root.style.setProperty('--primary-color', '#3498db');
    } else if (theme === 'dark') {
        root.style.setProperty('--background-color', '#2c3e50');
        root.style.setProperty('--text-color', '#ffffff');
        root.style.setProperty('--primary-color', '#3498db');
    }
}

// 调用函数切换主题
setTheme('dark');

2.5 变量的计算

CSS 变量可以与 calc() 函数结合使用,实现动态计算值。

:root {
    --base-font-size: 16px;
    --spacing-unit: 8px;
}

.element {
    font-size: var(--base-font-size);
    margin: calc(var(--spacing-unit) * 2); /* 16px */
    padding: calc(var(--spacing-unit) * 1.5); /* 12px */
    width: calc(100% - (var(--spacing-unit) * 4)); /* 100% - 32px */
}

.large-element {
    font-size: calc(var(--base-font-size) * 1.2); /* 19.2px */
}

.small-element {
    font-size: calc(var(--base-font-size) * 0.8); /* 12.8px */
}

3. 实用案例分析

3.1 主题切换

场景: 创建一个支持亮色和暗色主题切换的网页。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>主题切换示例</title>
    <style>
        /* 定义默认主题变量 */
        :root {
            --background-color: #ffffff;
            --text-color: #333333;
            --primary-color: #3498db;
            --secondary-color: #2ecc71;
            --accent-color: #f1c40f;
            --border-color: #dddddd;
            --card-background: #f9f9f9;
            --header-background: #f5f5f5;
            --footer-background: #f5f5f5;
            --transition-speed: 0.3s;
        }
        
        /* 暗色主题变量 */
        [data-theme="dark"] {
            --background-color: #1a1a1a;
            --text-color: #e0e0e0;
            --primary-color: #3498db;
            --secondary-color: #2ecc71;
            --accent-color: #f39c12;
            --border-color: #333333;
            --card-background: #2c2c2c;
            --header-background: #232323;
            --footer-background: #232323;
        }
        
        /* 全局样式 */
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            background-color: var(--background-color);
            color: var(--text-color);
            transition: background-color var(--transition-speed), color var(--transition-speed);
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 0 20px;
        }
        
        header {
            background-color: var(--header-background);
            padding: 20px 0;
            border-bottom: 1px solid var(--border-color);
            transition: background-color var(--transition-speed), border-color var(--transition-speed);
        }
        
        nav {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .logo {
            font-size: 24px;
            font-weight: bold;
            color: var(--primary-color);
            transition: color var(--transition-speed);
        }
        
        .nav-links {
            display: flex;
            gap: 20px;
        }
        
        .nav-links a {
            color: var(--text-color);
            text-decoration: none;
            transition: color var(--transition-speed);
        }
        
        .nav-links a:hover {
            color: var(--primary-color);
        }
        
        .theme-toggle {
            background-color: var(--primary-color);
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color var(--transition-speed);
        }
        
        .theme-toggle:hover {
            opacity: 0.9;
        }
        
        section {
            padding: 60px 0;
        }
        
        .section-title {
            font-size: 36px;
            margin-bottom: 40px;
            text-align: center;
            color: var(--primary-color);
            transition: color var(--transition-speed);
        }
        
        .card-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
            gap: 30px;
        }
        
        .card {
            background-color: var(--card-background);
            border-radius: 8px;
            padding: 30px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            transition: background-color var(--transition-speed);
        }
        
        .card-title {
            font-size: 20px;
            margin-bottom: 15px;
            color: var(--primary-color);
            transition: color var(--transition-speed);
        }
        
        .card-text {
            margin-bottom: 20px;
        }
        
        .btn {
            display: inline-block;
            padding: 10px 20px;
            background-color: var(--primary-color);
            color: white;
            text-decoration: none;
            border-radius: 4px;
            transition: background-color var(--transition-speed);
        }
        
        .btn:hover {
            opacity: 0.9;
        }
        
        footer {
            background-color: var(--footer-background);
            padding: 40px 0;
            border-top: 1px solid var(--border-color);
            text-align: center;
            transition: background-color var(--transition-speed), border-color var(--transition-speed);
        }
        
        @media (max-width: 768px) {
            .nav-links {
                display: none;
            }
            
            .card-grid {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <header>
        <div class="container">
            <nav>
                <div class="logo">My Website</div>
                <div class="nav-links">
                    <a href="#">首页</a>
                    <a href="#">关于我们</a>
                    <a href="#">产品中心</a>
                    <a href="#">联系我们</a>
                </div>
                <button class="theme-toggle" id="themeToggle">切换主题</button>
            </nav>
        </div>
    </header>
    
    <section>
        <div class="container">
            <h1 class="section-title">欢迎来到我们的网站</h1>
            <div class="card-grid">
                <div class="card">
                    <h2 class="card-title">专业设计</h2>
                    <p class="card-text">我们提供专业的网页设计服务,为您的企业打造独特的品牌形象。我们的设计师团队拥有丰富的经验,能够根据您的需求创造出美观、实用的网页设计。</p>
                    <a href="#" class="btn">了解更多</a>
                </div>
                <div class="card">
                    <h2 class="card-title">前端开发</h2>
                    <p class="card-text">我们的前端开发团队精通 HTML、CSS、JavaScript 等前端技术,能够将设计转化为功能完善、响应式的网页应用。我们注重代码质量和用户体验,确保网站在各种设备上都能正常运行。</p>
                    <a href="#" class="btn">了解更多</a>
                </div>
                <div class="card">
                    <h2 class="card-title">后端开发</h2>
                    <p class="card-text">我们提供专业的后端开发服务,为您的网站搭建稳定、安全的服务器端系统。我们的后端开发团队熟悉各种编程语言和框架,能够根据您的需求选择最合适的技术方案。</p>
                    <a href="#" class="btn">了解更多</a>
                </div>
            </div>
        </div>
    </section>
    
    <footer>
        <div class="container">
            <p>&copy; 2026 My Website. 保留所有权利。</p>
        </div>
    </footer>
    
    <script>
        const themeToggle = document.getElementById('themeToggle');
        const html = document.documentElement;
        
        // 检查本地存储中的主题设置
        const savedTheme = localStorage.getItem('theme');
        if (savedTheme) {
            html.setAttribute('data-theme', savedTheme);
        }
        
        // 切换主题
        themeToggle.addEventListener('click', () => {
            const currentTheme = html.getAttribute('data-theme');
            const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
            html.setAttribute('data-theme', newTheme);
            localStorage.setItem('theme', newTheme);
        });
    </script>
</body>
</html>

效果: 网页支持亮色和暗色主题切换,切换时会平滑过渡,并且主题设置会保存在本地存储中。

3.2 响应式设计

场景: 使用 CSS 变量创建响应式设计,根据屏幕尺寸自动调整布局和样式。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>响应式设计示例</title>
    <style>
        /* 定义变量 */
        :root {
            --base-font-size: 16px;
            --spacing-unit: 8px;
            --container-max-width: 1200px;
            --header-height: 60px;
            --footer-height: 80px;
            --primary-color: #3498db;
            --secondary-color: #2ecc71;
            --text-color: #333333;
            --background-color: #ffffff;
            --border-color: #dddddd;
            --card-padding: 20px;
            --card-border-radius: 8px;
            --grid-gap: 20px;
        }
        
        /* 响应式变量 */
        @media (max-width: 1200px) {
            :root {
                --container-max-width: 960px;
            }
        }
        
        @media (max-width: 992px) {
            :root {
                --container-max-width: 720px;
                --card-padding: 15px;
                --grid-gap: 15px;
            }
        }
        
        @media (max-width: 768px) {
            :root {
                --container-max-width: 540px;
                --base-font-size: 14px;
                --spacing-unit: 6px;
                --header-height: 50px;
                --footer-height: 60px;
            }
        }
        
        @media (max-width: 576px) {
            :root {
                --container-max-width: 100%;
                --card-padding: 10px;
                --grid-gap: 10px;
            }
        }
        
        /* 全局样式 */
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            font-size: var(--base-font-size);
            color: var(--text-color);
            background-color: var(--background-color);
        }
        
        .container {
            max-width: var(--container-max-width);
            margin: 0 auto;
            padding: 0 calc(var(--spacing-unit) * 2);
        }
        
        header {
            height: var(--header-height);
            background-color: var(--primary-color);
            color: white;
            display: flex;
            align-items: center;
            position: sticky;
            top: 0;
            z-index: 1000;
        }
        
        .header-content {
            display: flex;
            justify-content: space-between;
            align-items: center;
            width: 100%;
        }
        
        .logo {
            font-size: calc(var(--base-font-size) * 1.5);
            font-weight: bold;
        }
        
        nav ul {
            display: flex;
            list-style: none;
            gap: calc(var(--spacing-unit) * 3);
        }
        
        nav a {
            color: white;
            text-decoration: none;
            transition: opacity 0.3s;
        }
        
        nav a:hover {
            opacity: 0.8;
        }
        
        .mobile-menu-btn {
            display: none;
            background: none;
            border: none;
            color: white;
            font-size: 24px;
            cursor: pointer;
        }
        
        section {
            padding: calc(var(--spacing-unit) * 10) 0;
        }
        
        .section-title {
            font-size: calc(var(--base-font-size) * 2.5);
            margin-bottom: calc(var(--spacing-unit) * 5);
            text-align: center;
            color: var(--primary-color);
        }
        
        .card-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
            gap: var(--grid-gap);
        }
        
        .card {
            background-color: white;
            border: 1px solid var(--border-color);
            border-radius: var(--card-border-radius);
            padding: var(--card-padding);
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
        }
        
        .card-title {
            font-size: calc(var(--base-font-size) * 1.2);
            margin-bottom: calc(var(--spacing-unit) * 2);
            color: var(--primary-color);
        }
        
        .card-text {
            margin-bottom: calc(var(--spacing-unit) * 3);
        }
        
        .btn {
            display: inline-block;
            padding: calc(var(--spacing-unit) * 1.5) calc(var(--spacing-unit) * 3);
            background-color: var(--primary-color);
            color: white;
            text-decoration: none;
            border-radius: 4px;
            transition: background-color 0.3s;
        }
        
        .btn:hover {
            background-color: #2980b9;
        }
        
        footer {
            height: var(--footer-height);
            background-color: #333;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        
        /* 移动设备菜单 */
        @media (max-width: 768px) {
            .mobile-menu-btn {
                display: block;
            }
            
            nav ul {
                position: fixed;
                top: var(--header-height);
                left: 0;
                right: 0;
                background-color: var(--primary-color);
                flex-direction: column;
                align-items: center;
                padding: calc(var(--spacing-unit) * 3) 0;
                gap: calc(var(--spacing-unit) * 2);
                transform: translateY(-150%);
                transition: transform 0.3s;
                box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
            }
            
            nav ul.active {
                transform: translateY(0);
            }
        }
    </style>
</head>
<body>
    <header>
        <div class="container header-content">
            <div class="logo">My Website</div>
            <nav>
                <button class="mobile-menu-btn" id="mobileMenuBtn">☰</button>
                <ul id="navMenu">
                    <li><a href="#">首页</a></li>
                    <li><a href="#">关于我们</a></li>
                    <li><a href="#">产品中心</a></li>
                    <li><a href="#">联系我们</a></li>
                </ul>
            </nav>
        </div>
    </header>
    
    <section>
        <div class="container">
            <h1 class="section-title">响应式设计示例</h1>
            <div class="card-grid">
                <div class="card">
                    <h2 class="card-title">响应式布局</h2>
                    <p class="card-text">使用 CSS 变量和媒体查询创建响应式布局,根据屏幕尺寸自动调整内容的大小和排列方式,确保在各种设备上都能提供良好的用户体验。</p>
                    <a href="#" class="btn">了解更多</a>
                </div>
                <div class="card">
                    <h2 class="card-title">灵活的间距</h2>
                    <p class="card-text">使用 CSS 变量定义间距单位,在不同屏幕尺寸下自动调整间距大小,保持页面的美观和一致性。</p>
                    <a href="#" class="btn">了解更多</a>
                </div>
                <div class="card">
                    <h2 class="card-title">自适应字体</h2>
                    <p class="card-text">使用 CSS 变量定义基础字体大小,在不同屏幕尺寸下自动调整字体大小,确保文本在各种设备上都易于阅读。</p>
                    <a href="#" class="btn">了解更多</a>
                </div>
                <div class="card">
                    <h2 class="card-title">网格布局</h2>
                    <p class="card-text">使用 CSS Grid 和 CSS 变量创建灵活的网格布局,根据屏幕尺寸自动调整列数和间距,实现响应式的卡片排列。</p>
                    <a href="#" class="btn">了解更多</a>
                </div>
                <div class="card">
                    <h2 class="card-title">移动设备优化</h2>
                    <p class="card-text">针对移动设备优化导航菜单和内容布局,提供更好的触摸体验和页面性能。</p>
                    <a href="#" class="btn">了解更多</a>
                </div>
                <div class="card">
                    <h2 class="card-title">性能优化</h2>
                    <p class="card-text">通过合理使用 CSS 变量和媒体查询,减少 CSS 代码量,提高页面加载速度和渲染性能。</p>
                    <a href="#" class="btn">了解更多</a>
                </div>
            </div>
        </div>
    </section>
    
    <footer>
        <div class="container">
            <p>&copy; 2026 My Website. 保留所有权利。</p>
        </div>
    </footer>
    
    <script>
        const mobileMenuBtn = document.getElementById('mobileMenuBtn');
        const navMenu = document.getElementById('navMenu');
        
        mobileMenuBtn.addEventListener('click', () => {
            navMenu.classList.toggle('active');
        });
    </script>
</body>
</html>

效果: 网页会根据屏幕尺寸自动调整布局和样式,在不同设备上都能提供良好的用户体验。

3.3 动画控制

场景: 使用 CSS 变量控制动画参数,实现更加灵活和可维护的动画效果。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>动画控制示例</title>
    <style>
        /* 定义动画变量 */
        :root {
            --animation-duration: 2s;
            --animation-timing-function: ease-in-out;
            --animation-iteration-count: infinite;
            --animation-delay: 0s;
            --animation-direction: alternate;
            --animation-fill-mode: both;
            --primary-color: #3498db;
            --secondary-color: #e74c3c;
            --animation-distance: 100px;
            --animation-scale: 1.2;
            --animation-rotation: 180deg;
            --animation-opacity: 0.5;
        }
        
        /* 全局样式 */
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            background-color: #f5f5f5;
            color: #333;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 40px 20px;
        }
        
        h1 {
            text-align: center;
            margin-bottom: 40px;
            color: var(--primary-color);
        }
        
        .animation-container {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: center;
            align-items: center;
            margin-bottom: 40px;
        }
        
        .animation-item {
            width: 200px;
            height: 200px;
            background-color: var(--primary-color);
            border-radius: 8px;
            display: flex;
            justify-content: center;
            align-items: center;
            color: white;
            font-size: 18px;
            font-weight: bold;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
        }
        
        /* 平移动画 */
        .translate-animation {
            animation: translateAnimation var(--animation-duration) var(--animation-timing-function) var(--animation-iteration-count) var(--animation-delay) var(--animation-direction) var(--animation-fill-mode);
        }
        
        @keyframes translateAnimation {
            0% {
                transform: translateX(0);
            }
            100% {
                transform: translateX(var(--animation-distance));
            }
        }
        
        /* 缩放动画 */
        .scale-animation {
            animation: scaleAnimation var(--animation-duration) var(--animation-timing-function) var(--animation-iteration-count) var(--animation-delay) var(--animation-direction) var(--animation-fill-mode);
        }
        
        @keyframes scaleAnimation {
            0% {
                transform: scale(1);
            }
            100% {
                transform: scale(var(--animation-scale));
            }
        }
        
        /* 旋转动画 */
        .rotate-animation {
            animation: rotateAnimation var(--animation-duration) var(--animation-timing-function) var(--animation-iteration-count) var(--animation-delay) var(--animation-direction) var(--animation-fill-mode);
        }
        
        @keyframes rotateAnimation {
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(var(--animation-rotation));
            }
        }
        
        /* 透明度动画 */
        .opacity-animation {
            animation: opacityAnimation var(--animation-duration) var(--animation-timing-function) var(--animation-iteration-count) var(--animation-delay) var(--animation-direction) var(--animation-fill-mode);
        }
        
        @keyframes opacityAnimation {
            0% {
                opacity: 1;
            }
            100% {
                opacity: var(--animation-opacity);
            }
        }
        
        /* 颜色动画 */
        .color-animation {
            animation: colorAnimation var(--animation-duration) var(--animation-timing-function) var(--animation-iteration-count) var(--animation-delay) var(--animation-direction) var(--animation-fill-mode);
        }
        
        @keyframes colorAnimation {
            0% {
                background-color: var(--primary-color);
            }
            100% {
                background-color: var(--secondary-color);
            }
        }
        
        /* 控制面板 */
        .control-panel {
            background-color: white;
            border-radius: 8px;
            padding: 30px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }
        
        .control-group {
            margin-bottom: 20px;
        }
        
        .control-label {
            display: block;
            margin-bottom: 8px;
            font-weight: 500;
            color: #555;
        }
        
        .control-input {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 16px;
        }
        
        .control-range {
            width: 100%;
        }
        
        .control-value {
            display: inline-block;
            margin-left: 10px;
            font-size: 14px;
            color: #777;
            min-width: 60px;
        }
        
        .control-buttons {
            display: flex;
            gap: 10px;
            margin-top: 30px;
        }
        
        .btn {
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            font-size: 16px;
            font-weight: 500;
            cursor: pointer;
            transition: background-color 0.3s;
        }
        
        .btn-primary {
            background-color: var(--primary-color);
            color: white;
        }
        
        .btn-primary:hover {
            background-color: #2980b9;
        }
        
        .btn-secondary {
            background-color: #95a5a6;
            color: white;
        }
        
        .btn-secondary:hover {
            background-color: #7f8c8d;
        }
        
        @media (max-width: 768px) {
            .animation-container {
                flex-direction: column;
            }
            
            .control-buttons {
                flex-direction: column;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>CSS 变量动画控制示例</h1>
        
        <div class="animation-container">
            <div class="animation-item translate-animation">平移动画</div>
            <div class="animation-item scale-animation">缩放动画</div>
            <div class="animation-item rotate-animation">旋转动画</div>
            <div class="animation-item opacity-animation">透明度动画</div>
            <div class="animation-item color-animation">颜色动画</div>
        </div>
        
        <div class="control-panel">
            <h2 style="margin-bottom: 20px;">动画控制面板</h2>
            
            <div class="control-group">
                <label class="control-label" for="duration">动画持续时间 (秒)</label>
                <input type="range" class="control-range" id="duration" min="0.1" max="5" step="0.1" value="2">
                <span class="control-value" id="durationValue">2</span>
            </div>
            
            <div class="control-group">
                <label class="control-label" for="distance">平移距离 (px)</label>
                <input type="range" class="control-range" id="distance" min="10" max="300" step="10" value="100">
                <span class="control-value" id="distanceValue">100</span>
            </div>
            
            <div class="control-group">
                <label class="control-label" for="scale">缩放比例</label>
                <input type="range" class="control-range" id="scale" min="0.1" max="2" step="0.1" value="1.2">
                <span class="control-value" id="scaleValue">1.2</span>
            </div>
            
            <div class="control-group">
                <label class="control-label" for="rotation">旋转角度 (度)</label>
                <input type="range" class="control-range" id="rotation" min="0" max="360" step="15" value="180">
                <span class="control-value" id="rotationValue">180</span>
            </div>
            
            <div class="control-group">
                <label class="control-label" for="opacity">透明度</label>
                <input type="range" class="control-range" id="opacity" min="0" max="1" step="0.1" value="0.5">
                <span class="control-value" id="opacityValue">0.5</span>
            </div>
            
            <div class="control-buttons">
                <button class="btn btn-primary" id="resetBtn">重置动画</button>
                <button class="btn btn-secondary" id="randomBtn">随机参数</button>
            </div>
        </div>
    </div>
    
    <script>
        const root = document.documentElement;
        const durationSlider = document.getElementById('duration');
        const durationValue = document.getElementById('durationValue');
        const distanceSlider = document.getElementById('distance');
        const distanceValue = document.getElementById('distanceValue');
        const scaleSlider = document.getElementById('scale');
        const scaleValue = document.getElementById('scaleValue');
        const rotationSlider = document.getElementById('rotation');
        const rotationValue = document.getElementById('rotationValue');
        const opacitySlider = document.getElementById('opacity');
        const opacityValue = document.getElementById('opacityValue');
        const resetBtn = document.getElementById('resetBtn');
        const randomBtn = document.getElementById('randomBtn');
        const animationItems = document.querySelectorAll('.animation-item');
        
        // 更新持续时间
        durationSlider.addEventListener('input', () => {
            const value = durationSlider.value;
            durationValue.textContent = value;
            root.style.setProperty('--animation-duration', `${value}s`);
        });
        
        // 更新平移距离
        distanceSlider.addEventListener('input', () => {
            const value = distanceSlider.value;
            distanceValue.textContent = value;
            root.style.setProperty('--animation-distance', `${value}px`);
        });
        
        // 更新缩放比例
        scaleSlider.addEventListener('input', () => {
            const value = scaleSlider.value;
            scaleValue.textContent = value;
            root.style.setProperty('--animation-scale', value);
        });
        
        // 更新旋转角度
        rotationSlider.addEventListener('input', () => {
            const value = rotationSlider.value;
            rotationValue.textContent = value;
            root.style.setProperty('--animation-rotation', `${value}deg`);
        });
        
        // 更新透明度
        opacitySlider.addEventListener('input', () => {
            const value = opacitySlider.value;
            opacityValue.textContent = value;
            root.style.setProperty('--animation-opacity', value);
        });
        
        // 重置动画
        resetBtn.addEventListener('click', () => {
            durationSlider.value = 2;
            durationValue.textContent = '2';
            distanceSlider.value = 100;
            distanceValue.textContent = '100';
            scaleSlider.value = 1.2;
            scaleValue.textContent = '1.2';
            rotationSlider.value = 180;
            rotationValue.textContent = '180';
            opacitySlider.value = 0.5;
            opacityValue.textContent = '0.5';
            
            root.style.setProperty('--animation-duration', '2s');
            root.style.setProperty('--animation-distance', '100px');
            root.style.setProperty('--animation-scale', '1.2');
            root.style.setProperty('--animation-rotation', '180deg');
            root.style.setProperty('--animation-opacity', '0.5');
        });
        
        // 随机参数
        randomBtn.addEventListener('click', () => {
            const randomDuration = (Math.random() * 4 + 0.5).toFixed(1);
            const randomDistance = Math.floor(Math.random() * 200 + 50);
            const randomScale = (Math.random() * 1 + 0.5).toFixed(1);
            const randomRotation = Math.floor(Math.random() * 360);
            const randomOpacity = (Math.random() * 0.8 + 0.2).toFixed(1);
            
            durationSlider.value = randomDuration;
            durationValue.textContent = randomDuration;
            distanceSlider.value = randomDistance;
            distanceValue.textContent = randomDistance;
            scaleSlider.value = randomScale;
            scaleValue.textContent = randomScale;
            rotationSlider.value = randomRotation;
            rotationValue.textContent = randomRotation;
            opacitySlider.value = randomOpacity;
            opacityValue.textContent = randomOpacity;
            
            root.style.setProperty('--animation-duration', `${randomDuration}s`);
            root.style.setProperty('--animation-distance', `${randomDistance}px`);
            root.style.setProperty('--animation-scale', randomScale);
            root.style.setProperty('--animation-rotation', `${randomRotation}deg`);
            root.style.setProperty('--animation-opacity', randomOpacity);
        });
    </script>
</body>
</html>

效果: 网页显示五个具有不同动画效果的元素,用户可以通过控制面板调整动画参数,实时预览动画效果。

4. 浏览器兼容性

浏览器 支持情况
Chrome ✅ 支持 (49+)
Firefox ✅ 支持 (31+)
Safari ✅ 支持 (9.1+)
Edge ✅ 支持 (15+)
IE ❌ 不支持

5. 最佳实践

  1. 使用语义化的变量名:选择描述性的变量名,使代码更加易于理解和维护。

    /* 好的变量名 */
    :root {
        --primary-color: #3498db;
        --font-size-base: 16px;
        --spacing-unit: 8px;
    }
    
    /* 不好的变量名 */
    :root {
        --color1: #3498db;
        --fs: 16px;
        --sp: 8px;
    }
  2. 在 :root 中定义全局变量:对于需要在整个文档中使用的变量,在 :root 伪类中定义,使其成为全局变量。

  3. 使用局部变量:对于只在特定组件中使用的变量,在组件的选择器中定义,限制其作用域。

  4. 使用变量组织主题:使用变量组织颜色、字体、间距等主题相关的样式,便于主题切换和维护。

  5. 与 calc() 结合使用:使用变量与 calc() 函数结合,实现动态计算值,如响应式尺寸。

  6. 使用默认值:在使用变量时提供默认值,确保在变量未定义时也能正常显示。

    .element {
        color: var(--primary-color, blue);
    }
  7. 避免过度使用:不要为每个值都创建变量,只对需要重用或可能变化的值使用变量。

  8. 使用 CSS 变量进行动画控制:使用变量控制动画参数,实现更加灵活和可维护的动画效果。

  9. 结合 JavaScript 使用:通过 JavaScript 动态修改变量值,实现交互式的样式变化。

  10. 测试兼容性:由于 IE 不支持 CSS 变量,在需要支持 IE 的项目中,需要提供降级方案。

6. 总结

CSS 变量是 CSS3 中引入的一项强大功能,它为我们提供了一种灵活、可维护的方式来管理样式值。通过使用 CSS 变量,我们可以:

  1. 减少代码重复:定义一次变量,在多处使用,减少代码冗余。

  2. 提高可维护性:通过修改变量值,可以同时更新所有使用该变量的地方,减少维护成本。

  3. 实现主题切换:通过修改变量值,可以轻松实现亮色/暗色主题切换等功能。

  4. 创建响应式设计:结合媒体查询,使用变量定义响应式参数,实现更加灵活的响应式设计。

  5. 控制动画效果:使用变量控制动画参数,实现更加灵活和可维护的动画效果。

  6. 与 JavaScript 交互:通过 JavaScript 动态修改变量值,实现交互式的样式变化。

随着浏览器对 CSS 变量支持的不断完善,CSS 变量已经成为现代前端开发中不可或缺的一部分。掌握 CSS 变量的使用方法和高级特性,将使你能够更加高效地编写和维护 CSS 代码,提升前端开发的能力和水平。

« 上一篇 CSS 动画高级特性教程 下一篇 » CSS3 表单与表格 - 表单元素样式 - checkbox