CSS 变量
学习 CSS 变量的基本概念、CSS 变量的定义和使用、CSS 变量的作用域以及实际应用示例,掌握如何在 CSS 中使用变量提高代码的可维护性和灵活性。
CSS 变量概述
CSS 变量(也称为自定义属性)是 CSS3 引入的一种特性,允许开发者在 CSS 中定义可重用的值。使用 CSS 变量可以提高代码的可维护性、一致性和灵活性。
CSS 变量的优势
- 减少代码重复:通过定义变量,可以在多个地方重用相同的值,减少代码冗余。
- 提高可维护性:当需要修改一个值时,只需要修改变量的定义,而不需要在多个地方进行修改。
- 增强一致性:确保在整个项目中使用相同的值,避免不一致的情况。
- 支持动态更新:可以通过 JavaScript 动态修改 CSS 变量的值,实现动态样式变化。
- 支持计算:可以与 calc() 函数结合使用,实现复杂的计算。
- 作用域控制:可以在不同的作用域中定义变量,实现样式的模块化管理。
CSS 变量的定义和使用
1. 定义 CSS 变量
CSS 变量使用 --变量名 的语法在选择器中定义。
/* 在 :root 伪类中定义全局变量 */
:root {
--primary-color: #3498db;
--secondary-color: #2ecc71;
--font-size: 16px;
--spacing: 20px;
}
/* 在特定选择器中定义局部变量 */
.container {
--container-bg: #f0f0f0;
--container-padding: 15px;
}
2. 使用 CSS 变量
使用 var() 函数来引用 CSS 变量。
/* 使用 CSS 变量 */
.element {
color: var(--primary-color);
font-size: var(--font-size);
margin: var(--spacing);
}
/* 在特定选择器中使用局部变量 */
.container {
background-color: var(--container-bg);
padding: var(--container-padding);
}
3. var() 函数的语法
var(--变量名, 默认值),其中默认值是可选的,当变量未定义时使用。
/* 使用 var() 函数的默认值 */
.element {
color: var(--primary-color, blue); /* 如果 --primary-color 未定义,则使用 blue */
font-size: var(--font-size, 16px); /* 如果 --font-size 未定义,则使用 16px */
}
4. CSS 变量的命名规则
- 变量名必须以两个连字符(--)开头。
- 变量名可以包含字母、数字、下划线、连字符和 Unicode 字符。
- 变量名区分大小写,例如 --color 和 --COLOR 是不同的变量。
- 变量名最好使用语义化的名称,如 --primary-color、--font-size 等。
/* 有效的 CSS 变量名 */
:root {
--primary-color: #3498db;
--font-size: 16px;
--spacing: 20px;
--border-radius: 4px;
--text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
/* 无效的 CSS 变量名 */
:root {
/* 无效:没有以 -- 开头 */
primary-color: #3498db;
/* 无效:包含空格 */
--font size: 16px;
}
CSS 变量的作用域
CSS 变量的作用域是指变量在哪些元素中可用。CSS 变量的作用域由定义它的选择器决定。
1. 全局作用域
在 :root 伪类中定义的变量具有全局作用域,可以在整个文档中使用。
/* 全局变量 */
:root {
--primary-color: #3498db;
}
/* 在任何元素中都可以使用 */
h1 {
color: var(--primary-color);
}
p {
color: var(--primary-color);
}
.button {
background-color: var(--primary-color);
}
2. 局部作用域
在特定选择器中定义的变量具有局部作用域,只能在该选择器及其后代元素中使用。
/* 局部变量 */
.container {
--container-bg: #f0f0f0;
background-color: var(--container-bg);
}
/* 可以在后代元素中使用 */
.container p {
color: var(--container-bg); /* 可以使用,因为 p 是 .container 的后代 */
}
/* 不能在非后代元素中使用 */
.sidebar {
background-color: var(--container-bg); /* 不能使用,因为 .sidebar 不是 .container 的后代 */
}
3. 变量的继承
子元素会继承父元素定义的变量,如果子元素定义了同名变量,则会覆盖父元素的变量。
/* 父元素定义变量 */
.parent {
--color: red;
color: var(--color); /* 红色 */
}
/* 子元素继承父元素的变量 */
.child {
color: var(--color); /* 红色,继承自父元素 */
}
/* 子元素覆盖父元素的变量 */
.child-override {
--color: blue;
color: var(--color); /* 蓝色,覆盖了父元素的变量 */
}
4. 变量的优先级
CSS 变量的优先级遵循 CSS 的 cascade 规则,具体来说:
- 内联样式中定义的变量优先级最高。
- ID 选择器中定义的变量优先级高于类选择器。
- 类选择器中定义的变量优先级高于标签选择器。
- 标签选择器中定义的变量优先级高于全局变量。
- 后定义的变量会覆盖先定义的同名变量。
/* 全局变量 */
:root {
--color: red;
}
/* 标签选择器定义的变量 */
div {
--color: blue;
}
/* 类选择器定义的变量 */
.container {
--color: green;
}
/* ID 选择器定义的变量 */
#special {
--color: purple;
}
/* 使用变量 */
div {
color: var(--color); /* 蓝色,来自标签选择器 */
}
.container {
color: var(--color); /* 绿色,来自类选择器 */
}
#special {
color: var(--color); /* 紫色,来自 ID 选择器 */
}
/* 内联样式定义的变量优先级最高 */
/* <div style="--color: orange; color: var(--color);">橙色</div> */
CSS 变量的运算
CSS 变量可以与 calc() 函数结合使用,实现复杂的计算。
/* 定义变量 */
:root {
--base-font-size: 16px;
--spacing: 20px;
--border-width: 2px;
}
/* 使用 calc() 函数进行运算 */
.element {
font-size: calc(var(--base-font-size) * 1.2); /* 19.2px */
margin: calc(var(--spacing) * 1.5); /* 30px */
padding: calc(var(--spacing) - var(--border-width)); /* 18px */
width: calc(100% - var(--spacing) * 2); /* 100% 减去左右外边距 */
}
注意事项
calc()函数中的运算符两侧需要有空格。- 可以混合使用不同的单位,如像素和百分比。
- 可以使用括号来改变运算顺序。
CSS 变量与 JavaScript
可以通过 JavaScript 读取和修改 CSS 变量的值,实现动态样式变化。
1. 读取 CSS 变量
/* 读取 CSS 变量 */
// 方法 1:从根元素读取全局变量
const rootStyles = getComputedStyle(document.documentElement);
const primaryColor = rootStyles.getPropertyValue('--primary-color');
console.log(primaryColor); // 输出: #3498db
// 方法 2:从特定元素读取变量
const element = document.querySelector('.container');
const elementStyles = getComputedStyle(element);
const containerBg = elementStyles.getPropertyValue('--container-bg');
console.log(containerBg); // 输出: #f0f0f0
2. 修改 CSS 变量
/* 修改 CSS 变量 */
// 方法 1:修改根元素的全局变量
document.documentElement.style.setProperty('--primary-color', '#e74c3c');
// 方法 2:修改特定元素的变量
const element = document.querySelector('.container');
element.style.setProperty('--container-bg', '#e0f7fa');
// 示例:通过按钮点击修改变量
const button = document.querySelector('.change-color');
button.addEventListener('click', function() {
document.documentElement.style.setProperty('--primary-color', '#9b59b6');
});
3. 实际应用示例
<div class="theme-demo">
<h2>主题切换示例</h2>
<p>点击按钮切换主题颜色</p>
<button class="theme-button" data-theme="light">浅色主题</button>
<button class="theme-button" data-theme="dark">深色主题</button>
<button class="theme-button" data-theme="colorful">彩色主题</button>
</div>
<style>
/* 初始主题变量 */
:root {
--primary-color: #3498db;
--background-color: #ffffff;
--text-color: #333333;
}
.theme-demo {
background-color: var(--background-color);
color: var(--text-color);
padding: 20px;
border: 2px solid var(--primary-color);
border-radius: 4px;
}
.theme-demo h2 {
color: var(--primary-color);
}
.theme-button {
background-color: var(--primary-color);
color: white;
border: none;
padding: 10px 15px;
margin: 5px;
border-radius: 4px;
cursor: pointer;
}
</style>
<script>
// 主题配置
const themes = {
light: {
'--primary-color': '#3498db',
'--background-color': '#ffffff',
'--text-color': '#333333'
},
dark: {
'--primary-color': '#2c3e50',
'--background-color': '#34495e',
'--text-color': '#ecf0f1'
},
colorful: {
'--primary-color': '#e74c3c',
'--background-color': '#f1c40f',
'--text-color': '#2c3e50'
}
};
// 主题切换功能
const buttons = document.querySelectorAll('.theme-button');
buttons.forEach(button => {
button.addEventListener('click', function() {
const themeName = this.getAttribute('data-theme');
const theme = themes[themeName];
// 应用主题变量
for (const [property, value] of Object.entries(theme)) {
document.documentElement.style.setProperty(property, value);
}
});
});
</script>
CSS 变量实际应用示例
示例 1:颜色系统
/* 定义颜色系统变量 */
:root {
/* 主色调 */
--primary: #3498db;
--primary-light: #64b5f6;
--primary-dark: #2980b9;
/* 辅助色 */
--secondary: #2ecc71;
--secondary-light: #5efc82;
--secondary-dark: #27ae60;
/* 中性色 */
--white: #ffffff;
--gray-light: #f5f5f5;
--gray: #95a5a6;
--gray-dark: #34495e;
--black: #000000;
/* 功能色 */
--success: #2ecc71;
--warning: #f39c12;
--error: #e74c3c;
--info: #3498db;
}
/* 使用颜色变量 */
.header {
background-color: var(--primary);
color: var(--white);
}
.button-primary {
background-color: var(--primary);
color: var(--white);
}
.button-secondary {
background-color: var(--secondary);
color: var(--white);
}
.alert-success {
background-color: var(--success);
color: var(--white);
}
.alert-error {
background-color: var(--error);
color: var(--white);
}
示例 2:排版系统
/* 定义排版系统变量 */
:root {
/* 字体 */
--font-family-sans: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
--font-family-serif: 'Times New Roman', Times, serif;
--font-family-mono: 'Courier New', Courier, monospace;
/* 字体大小 */
--font-size-xs: 12px;
--font-size-sm: 14px;
--font-size-base: 16px;
--font-size-lg: 18px;
--font-size-xl: 20px;
--font-size-2xl: 24px;
--font-size-3xl: 30px;
--font-size-4xl: 36px;
/* 行高 */
--line-height-tight: 1.2;
--line-height-normal: 1.5;
--line-height-loose: 1.8;
/* 字重 */
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
}
/* 使用排版变量 */
body {
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
line-height: var(--line-height-normal);
font-weight: var(--font-weight-normal);
}
h1 {
font-size: var(--font-size-4xl);
line-height: var(--line-height-tight);
font-weight: var(--font-weight-bold);
}
h2 {
font-size: var(--font-size-3xl);
line-height: var(--line-height-tight);
font-weight: var(--font-weight-bold);
}
p {
font-size: var(--font-size-base);
line-height: var(--line-height-normal);
}
.small-text {
font-size: var(--font-size-sm);
}
.large-text {
font-size: var(--font-size-xl);
}
示例 3:间距系统
/* 定义间距系统变量 */
:root {
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--spacing-xl: 32px;
--spacing-2xl: 48px;
}
/* 使用间距变量 */
.container {
padding: var(--spacing-lg);
margin-bottom: var(--spacing-xl);
}
.card {
padding: var(--spacing-md);
margin-bottom: var(--spacing-lg);
}
.button {
padding: var(--spacing-sm) var(--spacing-md);
margin-right: var(--spacing-sm);
}
.section {
margin-top: var(--spacing-2xl);
margin-bottom: var(--spacing-2xl);
}
示例 4:动画系统
/* 定义动画系统变量 */
:root {
--animation-duration-fast: 0.2s;
--animation-duration-normal: 0.3s;
--animation-duration-slow: 0.5s;
--animation-ease-in: ease-in;
--animation-ease-out: ease-out;
--animation-ease-in-out: ease-in-out;
--animation-linear: linear;
}
/* 使用动画变量 */
.fade-in {
animation: fadeIn var(--animation-duration-normal) var(--animation-ease-in-out);
}
.slide-in {
animation: slideIn var(--animation-duration-slow) var(--animation-ease-out);
}
.button {
transition: background-color var(--animation-duration-fast) var(--animation-ease-in-out);
}
.card {
transition: transform var(--animation-duration-normal) var(--animation-ease-out);
}
.card:hover {
transform: translateY(-5px);
}
/* 定义动画 */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideIn {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
CSS 变量使用技巧
- 使用语义化的变量名:变量名应该清晰地表达其用途,如 --primary-color、--font-size-base 等。
- 组织变量结构:将变量按功能分组,如颜色、排版、间距、动画等,提高代码的可读性。
- 使用全局变量:对于在整个项目中使用的值,如主题色、基础字体大小等,应定义为全局变量。
- 使用局部变量:对于仅在特定组件中使用的值,应定义为局部变量,实现样式的模块化。
- 结合 calc() 使用:使用 calc() 函数与变量结合,可以实现复杂的计算,提高代码的灵活性。
- 使用默认值:在使用 var() 函数时,可以提供默认值,以防止变量未定义时出现问题。
- 通过 JavaScript 动态修改:利用 JavaScript 动态修改 CSS 变量,可以实现主题切换、响应式调整等功能。
- 注意浏览器兼容性:虽然现代浏览器都支持 CSS 变量,但在处理旧浏览器时需要考虑兼容性。
- 避免过度使用:对于不需要重用的值,不必定义为变量,避免代码冗余。
- 使用工具管理变量:对于大型项目,可以使用 CSS 预处理器(如 Sass、Less)或 PostCSS 插件来管理变量。
CSS 变量的浏览器兼容性
CSS 变量在现代浏览器中得到了广泛支持,但在一些旧浏览器中可能不被支持。
| 浏览器 | 支持版本 |
|---|---|
| Chrome | 49+ |
| Firefox | 31+ |
| Safari | 9.1+ |
| Edge | 15+ |
| IE | 不支持 |
兼容性处理
对于需要支持旧浏览器的项目,可以使用以下方法:
- 使用 CSS 预处理器:如 Sass、Less 等,它们的变量在编译时会被替换为实际值。
- 提供 fallback 值:在使用 CSS 变量时,提供传统的 CSS 属性作为 fallback。
- 使用 PostCSS 插件:如 postcss-custom-properties,可以在构建时将 CSS 变量转换为传统的 CSS。
/* 提供 fallback 值 */
.element {
/* 传统 CSS 属性作为 fallback */
color: blue;
/* CSS 变量 */
color: var(--primary-color, blue);
}
CSS 变量总结
- CSS 变量(自定义属性)使用
--变量名的语法定义,使用var()函数引用。 - CSS 变量具有作用域,全局变量定义在
:root中,局部变量定义在特定选择器中。 - CSS 变量支持继承,子元素会继承父元素定义的变量。
- CSS 变量可以与
calc()函数结合使用,实现复杂的计算。 - 可以通过 JavaScript 读取和修改 CSS 变量的值,实现动态样式变化。
- CSS 变量可以提高代码的可维护性、一致性和灵活性,减少代码冗余。
- CSS 变量在现代浏览器中得到了广泛支持,但在处理旧浏览器时需要考虑兼容性。
- 合理使用 CSS 变量,可以使 CSS 代码更加模块化、可维护和易于扩展。