CSS教程

CSS变量定义与使用

CSS变量定义与使用详解:声明和作用域

CSS变量(也称为自定义属性)是CSS3引入的一项强大功能,它允许开发者在样式表中定义可复用的值,并通过特定语法在整个文档中引用。找找网将为您详细讲解CSS变量的声明方法和作用域规则。

什么是CSS变量?

CSS变量(Custom Properties)是CSS3引入的一项革命性功能,它允许开发者在样式表中定义可复用的值,并通过特定语法在整个文档中引用。与传统预处理器变量不同,CSS变量是浏览器原生支持的,具有动态性和继承性两大核心特性。

CSS变量与预处理器变量的比较:

特性CSS变量SASS/LESS变量
编译时机运行时解析预编译时替换
作用域遵循DOM继承文件/块级作用域
动态修改支持JS实时更新编译后不可变
浏览器支持现代浏览器需编译为CSS

变量声明规范

基本声明语法

声明CSS变量必须遵循以下规则:

  • 以两个连字符开头(–)
  • 区分大小写(–color与–Color不同)
  • 可包含字母、数字、下划线和连字符
  • 通常在:root伪类中声明全局变量
:root {
  --main-bg-color: #ffffff;
  --header-height: 60px;
  --font-family-sans: "Helvetica", Arial, sans-serif;
}

变量命名规范

CSS变量的命名需要遵循特定规则:

  • 有效命名应包含字母数字字符、下划线和破折号
  • 变量名区分大小写
  • 不能包含空格和其他特殊字符

合法命名示例:

:root {
  --primary-color: #222;
  --_primary-color: #222;
  --12-primary-color: #222;
  --primay-color-12: #222;
}

非法命名示例:

:root {
  --primary color: #222; /* 不允许包含空格 */
  --primary$%#%$#; /* 不允许包含特殊字符 */
}

声明完整示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>CSS变量声明示例</title>
    <style>
        :root {
            --primary-color: #0066cc;
            --secondary-color: #ebf5ff;
            --base-spacing: 16px;
            --border-radius: 4px;
            --font-size-lg: 20px;
            --shadow: 0 2px 1px 0 rgba(0, 0, 0, 0.2);
        }

        body {
            font-family: Arial, sans-serif;
            padding: var(--base-spacing);
        }

        .card {
            padding: calc(var(--base-spacing) * 2);
            background-color: var(--secondary-color);
            border-radius: var(--border-radius);
            box-shadow: var(--shadow);
            margin-bottom: var(--base-spacing);
        }

        h1 {
            color: var(--primary-color);
            font-size: var(--font-size-lg);
        }
    </style>
</head>
<body>
    <div class="card">
        <h1>CSS变量声明示例</h1>
        <p>这个示例展示了如何在CSS中声明和使用变量。</p>
    </div>
</body>
</html>

变量作用域详解

作用域层级

CSS变量遵循DOM层级继承,具有以下作用域层级:

  • 全局作用域(:root)
  • 组件作用域(.component)
  • 局部作用域(特定选择器)
/* 全局变量 */
:root { 
  --text-color: #333; 
}

/* 组件级覆盖 */
.dark-mode { 
  --text-color: #eee; 
}

/* 元素级使用 */
p {
  color: var(--text-color);
}

作用域优先级

同一个CSS变量可以在多个选择器内声明,读取时优先级最高的声明生效,这与CSS的”层叠”规则一致。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>CSS变量作用域示例</title>
    <style>
        :root { 
            --color: blue; 
            --size: 16px;
        }
        div { 
            --color: green; 
        }
        #alert { 
            --color: red; 
            --size: 20px;
        }
        .special { 
            --color: purple; 
        }
        * { 
            color: var(--color); 
            font-size: var(--size);
        }
    </style>
</head>
<body>
    <p>蓝色(继承自:root)</p>
    <div>绿色(div作用域)</div>
    <div id="alert">红色(ID选择器优先级最高)</div>
    <div class="special">紫色(类选择器优先级高于元素选择器)</div>
</body>
</html>

作用域实际应用

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>CSS变量作用域实际应用</title>
    <style>
        :root {
            --primary: #0066cc;
            --spacing: 16px;
            --border: 1px solid #ddd;
        }

        .component {
            --primary: #dc004e;
            --spacing: 20px;
            border: var(--border);
            padding: var(--spacing);
            margin: var(--spacing);
        }

        .component h2 {
            color: var(--primary);
        }

        .component .nested {
            --primary: #00a86b;
            background-color: var(--primary);
            color: white;
            padding: calc(var(--spacing) / 2);
        }

        .global {
            color: var(--primary);
            padding: var(--spacing);
        }
    </style>
</head>
<body>
    <div class="global">
        这个元素使用全局变量,主色为蓝色。
    </div>

    <div class="component">
        <h2>这个组件有自己独立的作用域,主色为红色。</h2>
        <div class="nested">
            嵌套元素进一步覆盖了变量,主色为绿色。
        </div>
    </div>
</body>
</html>

var()函数使用详解

基本语法和使用

var()函数用于读取CSS变量,基本语法如下:

.element {
  property: var(--variable-name, fallback-value);
}

参数说明:

  • 第一个参数:变量名(必需)
  • 第二个参数:备用值(当变量未定义时使用)

备用值设置

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>CSS变量备用值示例</title>
    <style>
        :root {
            --primary-color: #0066cc;
            --warning-color: #ff9900;
        }

        .box {
            padding: 20px;
            margin: 10px;
            border-radius: 4px;
        }

        .primary {
            /* 使用已定义的变量 */
            background-color: var(--primary-color, blue);
        }

        .warning {
            /* 使用已定义的变量 */
            background-color: var(--warning-color, orange);
        }

        .success {
            /* 使用未定义的变量,回退到备用值 */
            background-color: var(--success-color, green);
        }

        .complex-fallback {
            /* 嵌套var()提供多层备用值 */
            background-color: var(--undefined-color, var(--another-undefined, purple));
        }
    </style>
</head>
<body>
    <div class="box primary">主要颜色(使用定义的变量)</div>
    <div class="box warning">警告颜色(使用定义的变量)</div>
    <div class="box success">成功颜色(使用备用值)</div>
    <div class="box complex-fallback">复杂备用值(使用最终备用值)</div>
</body>
</html>

变量值类型处理

CSS变量可以存储不同类型的值,使用时需要注意:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>CSS变量值类型处理</title>
    <style>
        :root {
            --text: "欢迎来到找找网";
            --size: 16;
            --color: #0066cc;
            --spacing: 10px;
        }

        .string-example::before {
            /* 字符串拼接 */
            content: var(--text) " - 学习CSS变量";
        }

        .number-example {
            /* 数值与单位直接连用是无效的 */
            /* font-size: var(--size)px; 这种方式无效 */
            font-size: calc(var(--size) * 1px);
            color: var(--color);
            margin: var(--spacing);
        }

        .calc-example {
            --width: 100;
            --height: 50;
            width: calc(var(--width) * 1px);
            height: calc(var(--height) * 1px);
            background-color: var(--color);
            margin: calc(var(--spacing) * 2);
        }
    </style>
</head>
<body>
    <div class="string-example"></div>
    <div class="number-example">这个示例展示如何处理数值类型的变量。</div>
    <div class="calc-example">使用calc()函数处理数值变量。</div>
</body>
</html>

高级应用场景

动态主题切换

CSS变量非常适合实现动态主题切换:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>CSS变量动态主题切换</title>
    <style>
        :root {
            --primary: #0066cc;
            --background: #ffffff;
            --text: #333333;
            --border: #dddddd;
            --shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        .dark-theme {
            --primary: #8ab4f8;
            --background: #202124;
            --text: #e8eaed;
            --border: #5f6368;
            --shadow: 0 2px 4px rgba(0,0,0,0.3);
        }

        body {
            background-color: var(--background);
            color: var(--text);
            font-family: Arial, sans-serif;
            padding: 20px;
            transition: all 0.3s ease;
        }

        .card {
            background-color: var(--background);
            border: 1px solid var(--border);
            border-radius: 8px;
            padding: 20px;
            margin: 10px 0;
            box-shadow: var(--shadow);
        }

        button {
            background-color: var(--primary);
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            cursor: pointer;
            margin: 5px;
        }

        .theme-controls {
            position: fixed;
            top: 20px;
            right: 20px;
        }
    </style>
</head>
<body>
    <div class="theme-controls">
        <button onclick="zzw_switchTheme('light')">浅色主题</button>
        <button onclick="zzw_switchTheme('dark')">深色主题</button>
    </div>

    <h1>CSS变量主题切换示例</h1>

    <div class="card">
        <h2>卡片标题</h2>
        <p>这是一个使用CSS变量实现主题切换的示例。点击右上角的按钮可以在浅色和深色主题之间切换。</p>
        <button>示例按钮</button>
    </div>

    <div class="card">
        <h2>另一张卡片</h2>
        <p>所有颜色都通过CSS变量定义,切换主题时只需更改变量的值。</p>
        <button>另一个按钮</button>
    </div>

    <script>
        function zzw_switchTheme(theme) {
            if (theme === 'dark') {
                document.body.classList.add('dark-theme');
            } else {
                document.body.classList.remove('dark-theme');
            }
        }
    </script>
</body>
</html>

响应式布局应用

结合媒体查询使用CSS变量创建响应式布局:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>CSS变量响应式布局</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        :root {
            --columns: 4;
            --gutter: 16px;
            --font-size: 14px;
            --card-padding: 20px;
        }

        @media (max-width: 768px) {
            :root {
                --columns: 2;
                --gutter: 12px;
                --font-size: 13px;
                --card-padding: 15px;
            }
        }

        @media (max-width: 480px) {
            :root {
                --columns: 1;
                --gutter: 8px;
                --font-size: 12px;
                --card-padding: 10px;
            }
        }

        body {
            font-family: Arial, sans-serif;
            padding: var(--gutter);
        }

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

        .card {
            background: #f5f5f5;
            border-radius: 4px;
            padding: var(--card-padding);
            font-size: var(--font-size);
        }

        .info {
            margin-top: 20px;
            padding: 10px;
            background: #e9e9e9;
            border-radius: 4px;
        }
    </style>
</head>
<body>
    <h1>CSS变量响应式布局示例</h1>

    <div class="grid">
        <div class="card">网格项 1</div>
        <div class="card">网格项 2</div>
        <div class="card">网格项 3</div>
        <div class="card">网格项 4</div>
        <div class="card">网格项 5</div>
        <div class="card">网格项 6</div>
        <div class="card">网格项 7</div>
        <div class="card">网格项 8</div>
    </div>

    <div class="info">
        <p>尝试调整浏览器窗口大小,观察布局和样式如何根据CSS变量的变化而自适应调整。</p>
        <p>当前列数:<span id="zzw_columnDisplay"></span></p>
        <p>当前间距:<span id="zzw_gutterDisplay"></span></p>
    </div>

    <script>
        function zzw_updateDisplay() {
            const styles = getComputedStyle(document.documentElement);
            const columns = styles.getPropertyValue('--columns').trim();
            const gutter = styles.getPropertyValue('--gutter').trim();

            document.getElementById('zzw_columnDisplay').textContent = columns;
            document.getElementById('zzw_gutterDisplay').textContent = gutter;
        }

        // 初始更新
        zzw_updateDisplay();

        // 窗口大小变化时更新
        window.addEventListener('resize', zzw_updateDisplay);
    </script>
</body>
</html>

与JavaScript交互

CSS变量可以通过JavaScript动态操作:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>CSS变量与JavaScript交互</title>
    <style>
        :root {
            --rotate: 0deg;
            --scale: 1;
            --translateX: 0px;
            --color: #0066cc;
        }

        .box {
            width: 100px;
            height: 100px;
            background-color: var(--color);
            margin: 50px auto;
            transform: 
                rotate(var(--rotate)) 
                scale(var(--scale)) 
                translateX(var(--translateX));
            transition: transform 0.3s ease;
        }

        .controls {
            display: flex;
            flex-direction: column;
            max-width: 300px;
            margin: 0 auto;
            gap: 10px;
        }

        .control-group {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        label {
            width: 80px;
        }

        input[type="range"] {
            flex: 1;
        }

        .value-display {
            width: 50px;
            text-align: right;
        }
    </style>
</head>
<body>
    <h1>CSS变量与JavaScript交互示例</h1>

    <div class="box" id="zzw_targetBox"></div>

    <div class="controls">
        <div class="control-group">
            <label for="zzw_rotateControl">旋转:</label>
            <input type="range" id="zzw_rotateControl" min="0" max="360" value="0">
            <span class="value-display" id="zzw_rotateValue">0deg</span>
        </div>

        <div class="control-group">
            <label for="zzw_scaleControl">缩放:</label>
            <input type="range" id="zzw_scaleControl" min="50" max="150" value="100">
            <span class="value-display" id="zzw_scaleValue">1</span>
        </div>

        <div class="control-group">
            <label for="zzw_translateControl">平移:</label>
            <input type="range" id="zzw_translateControl" min="-100" max="100" value="0">
            <span class="value-display" id="zzw_translateValue">0px</span>
        </div>

        <div class="control-group">
            <label for="zzw_colorControl">颜色:</label>
            <input type="color" id="zzw_colorControl" value="#0066cc">
            <span class="value-display" id="zzw_colorValue">#0066cc</span>
        </div>

        <button onclick="zzw_resetValues()">重置值</button>
    </div>

    <script>
        // 获取DOM元素
        const zzw_rotateControl = document.getElementById('zzw_rotateControl');
        const zzw_scaleControl = document.getElementById('zzw_scaleControl');
        const zzw_translateControl = document.getElementById('zzw_translateControl');
        const zzw_colorControl = document.getElementById('zzw_colorControl');

        const zzw_rotateValue = document.getElementById('zzw_rotateValue');
        const zzw_scaleValue = document.getElementById('zzw_scaleValue');
        const zzw_translateValue = document.getElementById('zzw_translateValue');
        const zzw_colorValue = document.getElementById('zzw_colorValue');

        // 设置CSS变量值
        function zzw_setCSSVariable(name, value) {
            document.documentElement.style.setProperty(name, value);
        }

        // 获取CSS变量值
        function zzw_getCSSVariable(name) {
            return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
        }

        // 更新旋转
        zzw_rotateControl.addEventListener('input', function() {
            const value = this.value + 'deg';
            zzw_setCSSVariable('--rotate', value);
            zzw_rotateValue.textContent = value;
        });

        // 更新缩放
        zzw_scaleControl.addEventListener('input', function() {
            const value = this.value / 100;
            zzw_setCSSVariable('--scale', value);
            zzw_scaleValue.textContent = value;
        });

        // 更新平移
        zzw_translateControl.addEventListener('input', function() {
            const value = this.value + 'px';
            zzw_setCSSVariable('--translateX', value);
            zzw_translateValue.textContent = value;
        });

        // 更新颜色
        zzw_colorControl.addEventListener('input', function() {
            const value = this.value;
            zzw_setCSSVariable('--color', value);
            zzw_colorValue.textContent = value;
        });

        // 重置值
        function zzw_resetValues() {
            zzw_rotateControl.value = 0;
            zzw_scaleControl.value = 100;
            zzw_translateControl.value = 0;
            zzw_colorControl.value = '#0066cc';

            zzw_setCSSVariable('--rotate', '0deg');
            zzw_setCSSVariable('--scale', '1');
            zzw_setCSSVariable('--translateX', '0px');
            zzw_setCSSVariable('--color', '#0066cc');

            zzw_rotateValue.textContent = '0deg';
            zzw_scaleValue.textContent = '1';
            zzw_translateValue.textContent = '0px';
            zzw_colorValue.textContent = '#0066cc';
        }

        // 初始化显示值
        zzw_rotateValue.textContent = zzw_getCSSVariable('--rotate');
        zzw_scaleValue.textContent = zzw_getCSSVariable('--scale');
        zzw_translateValue.textContent = zzw_getCSSVariable('--translateX');
        zzw_colorValue.textContent = zzw_getCSSVariable('--color');
    </script>
</body>
</html>

兼容性处理和最佳实践

浏览器兼容性处理

虽然现代浏览器对CSS变量有很好的支持,但仍需考虑兼容性处理:

/* 提供备用值 */
.legacy-box {
  width: 300px; /* 旧浏览器备用值 */
  width: var(--box-width, 300px);
}

/* 使用@supports进行特性检测 */
@supports (--css: variables) {
  .modern-element {
    color: var(--primary-color);
  }
}

@supports not (--css: variables) {
  .modern-element {
    color: #0066cc;
  }
}

最佳实践建议

  1. 命名规范
  • 使用语义化命名(–color-text-primary而非–red)
  • 设计系统分级(–space-md、–font-size-lg)
  • 前缀约定(–ds-color-primary用于设计系统)
  1. 组织管理策略
  • 按功能分类组织变量
  • 使用单独文件管理主要变量
  1. 调试技巧
  • 使用浏览器开发者工具查看和修改变量值
  • 在Elements面板中查看计算后的变量值

总结

知识点总结

知识点内容说明
变量声明使用--前缀声明CSS变量,通常在:root中定义全局变量
变量命名区分大小写,可包含字母、数字、下划线和连字符,不能包含空格
var()函数用于读取变量值,支持备用值参数
变量作用域遵循CSS层叠规则,可在不同选择器中定义不同作用域的变量
值类型处理字符串可拼接,数值需配合calc()使用,不能直接连接单位
主题切换通过覆盖变量值实现动态主题切换
响应式设计结合媒体查询修改变量值实现响应式布局
JavaScript操作使用setProperty()、getPropertyValue()方法操作变量
兼容性处理使用备用值和@supports规则处理浏览器兼容性

CSS变量功能强大且灵活,正确使用可以大幅提高CSS代码的维护性和复用性。找找网建议在实际项目中逐步应用CSS变量,从简单的颜色和间距开始,逐步扩展到更复杂的应用场景。