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; /* 定义字体大小变量为16像素 */
--spacing: 20px; /* 定义间距变量为20像素 */
}
/* 在特定选择器中定义局部变量 */
.container {
--container-bg: #f0f0f0; /* 定义容器背景色变量为浅灰色 */
--container-padding: 15px; /* 定义容器内边距变量为15像素 */
}
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); /* 使用主色调变量设置文本颜色,如果变量未定义则使用蓝色作为默认值 */
font-size: var(--font-size, 16px); /* 使用字体大小变量设置字体大小,如果变量未定义则使用16像素作为默认值 */
}
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); /* 使用全局主色调变量设置h1标题颜色 */
}
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; /* ID选择器定义颜色变量为紫色,优先级高于类选择器 */
}
/* 使用变量 */
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; /* 定义基础字体大小变量为16像素 */
--spacing: 20px; /* 定义间距变量为20像素 */
--border-width: 2px; /* 定义边框宽度变量为2像素 */
}
/* 使用 calc() 函数进行运算 */
.element {
font-size: calc(var(--base-font-size) * 1.2); /* 使用calc()函数计算字体大小为基础字体大小的1.2倍,结果为19.2像素 */
margin: calc(var(--spacing) * 1.5); /* 使用calc()函数计算外边距为间距的1.5倍,结果为30像素 */
padding: calc(var(--spacing) - var(--border-width)); /* 使用calc()函数计算内边距为间距减去边框宽度,结果为18像素 */
width: calc(100% - var(--spacing) * 2); /* 使用calc()函数计算宽度为100%减去两倍间距,结果为100%减去左右外边距 */
}
注意事项
calc()函数中的运算符两侧需要有空格。- 可以混合使用不同的单位,如像素和百分比。
- 可以使用括号来改变运算顺序。
CSS 变量与 JavaScript
可以通过 JavaScript 读取和修改 CSS 变量的值,实现动态样式变化。
1. 读取 CSS 变量
/* 读取 CSS 变量 */
// 方法 1:从根元素读取全局变量
const rootStyles = getComputedStyle(document.documentElement); // 获取根元素的计算样式
const primaryColor = rootStyles.getPropertyValue('--primary-color'); // 从计算样式中获取--primary-color变量的值
console.log(primaryColor); // 输出: #3498db
// 方法 2:从特定元素读取变量
const element = document.querySelector('.container'); // 获取.container元素
const elementStyles = getComputedStyle(element); // 获取.container元素的计算样式
const containerBg = elementStyles.getPropertyValue('--container-bg'); // 从计算样式中获取--container-bg变量的值
console.log(containerBg); // 输出: #f0f0f0
2. 修改 CSS 变量
/* 修改 CSS 变量 */
// 方法 1:修改根元素的全局变量
document.documentElement.style.setProperty('--primary-color', '#e74c3c'); // 修改根元素的--primary-color变量值为#e74c3c(红色)
// 方法 2:修改特定元素的变量
const element = document.querySelector('.container'); // 获取.container元素
element.style.setProperty('--container-bg', '#e0f7fa'); // 修改.container元素的--container-bg变量值为#e0f7fa(浅蓝色)
// 示例:通过按钮点击修改变量
const button = document.querySelector('.change-color'); // 获取.change-color按钮元素
button.addEventListener('click', function() { // 为按钮添加点击事件监听器
document.documentElement.style.setProperty('--primary-color', '#9b59b6'); // 点击时修改根元素的--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; /* 设置内边距为20像素 */
border: 2px solid var(--primary-color); /* 使用主色调变量设置边框颜色 */
border-radius: 4px; /* 设置边框圆角为4像素 */
}
.theme-demo h2 {
color: var(--primary-color); /* 使用主色调变量设置h2标题颜色 */
}
.theme-button {
background-color: var(--primary-color); /* 使用主色调变量设置按钮背景颜色 */
color: white; /* 设置按钮文本颜色为白色 */
border: none; /* 移除按钮边框 */
padding: 10px 15px; /* 设置按钮内边距为10像素(上下)和15像素(左右) */
margin: 5px; /* 设置按钮外边距为5像素 */
border-radius: 4px; /* 设置按钮边框圆角为4像素 */
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'); // 获取所有.theme-button元素
buttons.forEach(button => { // 遍历所有按钮
button.addEventListener('click', function() { // 为每个按钮添加点击事件监听器
const themeName = this.getAttribute('data-theme'); // 获取当前按钮的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; /* 定义极小字体大小变量为12像素 */
--font-size-sm: 14px; /* 定义小字体大小变量为14像素 */
--font-size-base: 16px; /* 定义基础字体大小变量为16像素 */
--font-size-lg: 18px; /* 定义大字体大小变量为18像素 */
--font-size-xl: 20px; /* 定义超大字体大小变量为20像素 */
--font-size-2xl: 24px; /* 定义2倍超大字体大小变量为24像素 */
--font-size-3xl: 30px; /* 定义3倍超大字体大小变量为30像素 */
--font-size-4xl: 36px; /* 定义4倍超大字体大小变量为36像素 */
/* 行高 */
--line-height-tight: 1.2; /* 定义紧凑行高变量为1.2 */
--line-height-normal: 1.5; /* 定义正常行高变量为1.5 */
--line-height-loose: 1.8; /* 定义宽松行高变量为1.8 */
/* 字重 */
--font-weight-normal: 400; /* 定义正常字重变量为400 */
--font-weight-medium: 500; /* 定义中等字重变量为500 */
--font-weight-semibold: 600; /* 定义半粗体字重变量为600 */
--font-weight-bold: 700; /* 定义粗体字重变量为700 */
}
/* 使用排版变量 */
body {
font-family: var(--font-family-sans); /* 使用无衬线字体变量设置body字体 */
font-size: var(--font-size-base); /* 使用基础字体大小变量设置body字体大小 */
line-height: var(--line-height-normal); /* 使用正常行高变量设置body行高 */
font-weight: var(--font-weight-normal); /* 使用正常字重变量设置body字重 */
}
h1 {
font-size: var(--font-size-4xl); /* 使用4倍超大字体大小变量设置h1字体大小 */
line-height: var(--line-height-tight); /* 使用紧凑行高变量设置h1行高 */
font-weight: var(--font-weight-bold); /* 使用粗体字重变量设置h1字重 */
}
h2 {
font-size: var(--font-size-3xl); /* 使用3倍超大字体大小变量设置h2字体大小 */
line-height: var(--line-height-tight); /* 使用紧凑行高变量设置h2行高 */
font-weight: var(--font-weight-bold); /* 使用粗体字重变量设置h2字重 */
}
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; /* 定义极小间距变量为4像素 */
--spacing-sm: 8px; /* 定义小间距变量为8像素 */
--spacing-md: 16px; /* 定义中等间距变量为16像素 */
--spacing-lg: 24px; /* 定义大间距变量为24像素 */
--spacing-xl: 32px; /* 定义超大间距变量为32像素 */
--spacing-2xl: 48px; /* 定义2倍超大间距变量为48像素 */
}
/* 使用间距变量 */
.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); /* 使用2倍超大间距变量设置区块上方外边距 */
margin-bottom: var(--spacing-2xl); /* 使用2倍超大间距变量设置区块下方外边距 */
}
示例 4:动画系统
/* 定义动画系统变量 */
:root {
--animation-duration-fast: 0.2s; /* 定义快速动画持续时间变量为0.2秒 */
--animation-duration-normal: 0.3s; /* 定义正常动画持续时间变量为0.3秒 */
--animation-duration-slow: 0.5s; /* 定义慢速动画持续时间变量为0.5秒 */
--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); /* 鼠标悬停时卡片向上移动5像素 */
}
/* 定义动画 */
@keyframes fadeIn {
from {
opacity: 0; /* 动画开始时元素完全透明 */
}
to {
opacity: 1; /* 动画结束时元素完全不透明 */
}
}
@keyframes slideIn {
from {
transform: translateX(-100%); /* 动画开始时元素从左侧100%位置进入 */
}
to {
transform: translateX(0); /* 动画结束时元素到达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属性作为fallback,当CSS变量不被支持时使用 */
/* CSS 变量 */
color: var(--primary-color, blue); /* 使用CSS变量设置颜色,如果变量未定义或浏览器不支持则使用蓝色作为默认值 */
}
CSS 变量总结
- CSS 变量(自定义属性)使用
--变量名的语法定义,使用var()函数引用。 - CSS 变量具有作用域,全局变量定义在
:root中,局部变量定义在特定选择器中。 - CSS 变量支持继承,子元素会继承父元素定义的变量。
- CSS 变量可以与
calc()函数结合使用,实现复杂的计算。 - 可以通过 JavaScript 读取和修改 CSS 变量的值,实现动态样式变化。
- CSS 变量可以提高代码的可维护性、一致性和灵活性,减少代码冗余。
- CSS 变量在现代浏览器中得到了广泛支持,但在处理旧浏览器时需要考虑兼容性。
- 合理使用 CSS 变量,可以使 CSS 代码更加模块化、可维护和易于扩展。