CSS变量与预处理器
CSS变量(自定义属性)和预处理器是现代CSS开发的重要工具,它们提供了变量、嵌套、混合宏等功能,大大提高了CSS的可维护性和开发效率。本文将深入讲解CSS变量和预处理器的核心概念、使用方法和最佳实践。
参考资料
一、CSS变量(自定义属性)
1.1 什么是CSS变量
CSS变量(CSS Custom Properties)是CSS中定义可重用值的特性。它们以 -- 开头,通过 var() 函数使用。
1.2 基本语法
定义变量:
css
/* 在:root中定义全局变量 */
:root {
--primary-color: #007bff;
--secondary-color: #6c757d;
--font-size-base: 16px;
--spacing-unit: 8px;
}
/* 在特定选择器中定义局部变量 */
.card {
--card-bg: white;
--card-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
使用变量:
css
.button {
background-color: var(--primary-color);
font-size: var(--font-size-base);
padding: var(--spacing-unit) calc(var(--spacing-unit) * 2);
}
.card {
background-color: var(--card-bg);
box-shadow: var(--card-shadow);
}
1.3 变量作用域
css
/* 全局变量 */
:root {
--global-color: red;
}
/* 局部变量 */
.container {
--local-color: blue;
}
/* 使用变量 */
.box {
color: var(--local-color, var(--global-color)); /* 优先使用局部变量 */
}
1.4 变量默认值
css
.box {
/* 使用默认值 */
color: var(--primary-color, #007bff);
/* 嵌套默认值 */
background-color: var(--bg-color, var(--default-bg, white));
}
1.5 动态修改变量
JavaScript修改:
javascript
// 修改CSS变量
document.documentElement.style.setProperty('--primary-color', '#ff0000');
// 获取CSS变量
const primaryColor = getComputedStyle(document.documentElement)
.getPropertyValue('--primary-color');
媒体查询中修改:
css
:root {
--font-size: 16px;
}
@media (max-width: 767px) {
:root {
--font-size: 14px;
}
}
二、CSS变量实战
2.1 主题切换
css
/* 默认主题(浅色) */
:root {
--bg-color: #ffffff;
--text-color: #333333;
--primary-color: #007bff;
--border-color: #dddddd;
}
/* 深色主题 */
[data-theme="dark"] {
--bg-color: #1a1a1a;
--text-color: #ffffff;
--primary-color: #4dabf7;
--border-color: #444444;
}
/* 使用变量 */
body {
background-color: var(--bg-color);
color: var(--text-color);
}
.button {
background-color: var(--primary-color);
border: 1px solid var(--border-color);
}
javascript
// 主题切换
function toggleTheme() {
const currentTheme = document.documentElement.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
}
2.2 响应式设计
css
:root {
--spacing: 20px;
--font-size: 16px;
--container-width: 1200px;
}
@media (max-width: 767px) {
:root {
--spacing: 10px;
--font-size: 14px;
--container-width: 100%;
}
}
.container {
max-width: var(--container-width);
margin: 0 auto;
padding: 0 var(--spacing);
}
2.3 组件样式
css
/* 按钮组件 */
.button {
--button-bg: var(--primary-color);
--button-text: white;
--button-padding: 12px 24px;
--button-radius: 4px;
background-color: var(--button-bg);
color: var(--button-text);
padding: var(--button-padding);
border-radius: var(--button-radius);
border: none;
cursor: pointer;
}
/* 按钮变体 */
.button--secondary {
--button-bg: var(--secondary-color);
}
.button--danger {
--button-bg: #dc3545;
}
.button--small {
--button-padding: 8px 16px;
--button-radius: 2px;
}
2.4 网格系统
css
:root {
--grid-columns: 12;
--grid-gutter: 20px;
}
.grid {
display: grid;
grid-template-columns: repeat(var(--grid-columns), 1fr);
gap: var(--grid-gutter);
}
.col-1 { grid-column: span 1; }
.col-2 { grid-column: span 2; }
.col-3 { grid-column: span 3; }
/* ... */
.col-12 { grid-column: span 12; }
@media (max-width: 767px) {
.col-sm-12 { grid-column: span 12; }
}
三、Sass预处理器
3.1 什么是Sass
Sass(Syntactically Awesome Style Sheets)是一个CSS预处理器,它扩展了CSS的功能,提供了变量、嵌套、混合宏、函数等特性。
3.2 Sass安装
bash
# 使用npm安装
npm install -g sass
# 或者使用yarn
yarn global add sass
3.3 Sass编译
bash
# 编译单个文件
sass input.scss output.css
# 监听文件变化
sass --watch input.scss:output.css
# 编译整个目录
sass --watch scss:css
3.4 Sass变量
scss
// 变量定义
$primary-color: #007bff;
$secondary-color: #6c757d;
$font-size-base: 16px;
$spacing-unit: 8px;
// 变量使用
.button {
background-color: $primary-color;
font-size: $font-size-base;
padding: $spacing-unit * 2;
}
// 变量作用域
.container {
$local-var: 10px;
padding: $local-var;
}
// 默认变量
$primary-color: #007bff !default;
3.5 Sass嵌套
scss
// 选择器嵌套
.nav {
background-color: #333;
.nav-item {
display: inline-block;
.nav-link {
color: white;
text-decoration: none;
&:hover {
color: #ddd;
}
&.active {
color: #007bff;
}
}
}
}
// 属性嵌合
.box {
font: {
family: Arial, sans-serif;
size: 16px;
weight: bold;
}
border: {
width: 1px;
style: solid;
color: #ddd;
}
}
3.6 Sass混合宏(Mixins)
scss
// 定义混合宏
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
@mixin flex-between {
display: flex;
justify-content: space-between;
align-items: center;
}
// 带参数的混合宏
@mixin button-style($bg-color, $text-color: white) {
background-color: $bg-color;
color: $text-color;
padding: 12px 24px;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
opacity: 0.9;
}
}
// 使用混合宏
.container {
@include flex-center;
}
.button {
@include button-style(#007bff);
}
.button--danger {
@include button-style(#dc3545);
}
3.7 Sass函数
scss
// 自定义函数
@function calculate-rem($px, $base: 16px) {
@return $px / $base * 1rem;
}
// 使用函数
.box {
font-size: calculate-rem(18px);
padding: calculate-rem(20px);
}
// 内置函数
$color: #007bff;
.lighter {
color: lighten($color, 20%);
}
.darker {
color: darken($color, 20%);
}
.transparent {
color: transparentize($color, 0.5);
}
3.8 Sass继承
scss
// 定义基础样式
%base-button {
padding: 12px 24px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
// 继承基础样式
.button {
@extend %base-button;
background-color: #007bff;
color: white;
}
.button--danger {
@extend %base-button;
background-color: #dc3545;
color: white;
}
四、Less预处理器
4.1 什么是Less
Less(Leaner Style Sheets)是另一个CSS预处理器,它扩展了CSS的动态行为,如变量、混合宏、函数等。
4.2 Less安装
bash
# 使用npm安装
npm install -g less
# 或者使用yarn
yarn global add less
4.3 Less编译
bash
# 编译单个文件
lessc input.less output.css
# 压缩输出
lessc input.less output.css --clean-css
4.4 Less变量
less
// 变量定义
@primary-color: #007bff;
@secondary-color: #6c757d;
@font-size-base: 16px;
@spacing-unit: 8px;
// 变量使用
.button {
background-color: @primary-color;
font-size: @font-size-base;
padding: @spacing-unit * 2;
}
// 变量插值
@selector: box;
.@{selector} {
width: 100px;
}
4.5 Less混合宏
less
// 定义混合宏
.flex-center() {
display: flex;
justify-content: center;
align-items: center;
}
.flex-between() {
display: flex;
justify-content: space-between;
align-items: center;
}
// 带参数的混合宏
.button-style(@bg-color, @text-color: white) {
background-color: @bg-color;
color: @text-color;
padding: 12px 24px;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
opacity: 0.9;
}
}
// 使用混合宏
.container {
.flex-center();
}
.button {
.button-style(#007bff);
}
.button--danger {
.button-style(#dc3545);
}
4.6 Less函数
less
// 自定义函数
.calculate-rem(@px, @base: 16px) {
@result: @px / @base * 1rem;
}
// 使用函数
.box {
.calculate-rem(18px);
font-size: @result;
}
// 内置函数
@color: #007bff;
.lighter {
color: lighten(@color, 20%);
}
.darker {
color: darken(@color, 20%);
}
4.7 Less嵌套
less
// 选择器嵌套
.nav {
background-color: #333;
.nav-item {
display: inline-block;
.nav-link {
color: white;
text-decoration: none;
&:hover {
color: #ddd;
}
&.active {
color: #007bff;
}
}
}
}
五、PostCSS
5.1 什么是PostCSS
PostCSS是一个用JavaScript转换CSS的工具,它通过插件系统提供了各种功能,如自动添加浏览器前缀、压缩CSS、使用未来CSS语法等。
5.2 PostCSS安装
bash
# 使用npm安装
npm install -g postcss-cli autoprefixer
# 或者使用yarn
yarn global add postcss-cli autoprefixer
5.3 PostCSS配置
javascript
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer'),
require('cssnano')({
preset: 'default',
}),
],
};
5.4 常用PostCSS插件
Autoprefixer:自动添加浏览器前缀
css
/* 输入 */
.box {
display: flex;
transform: rotate(10deg);
}
/* 输出 */
.box {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-transform: rotate(10deg);
transform: rotate(10deg);
}
cssnano:压缩CSS
css
/* 输入 */
.box {
color: #ff0000;
background-color: #000000;
margin: 10px 20px 10px 20px;
}
/* 输出 */
.box{color:red;background-color:#000;margin:10px 20px}
postcss-preset-env:使用未来CSS语法
css
/* 输入 */
.box {
color: oklch(40% 0.2 250);
}
/* 输出 */
.box {
color: rgb(0, 82, 204);
}
六、CSS变量 vs 预处理器
6.1 功能对比
| 功能 | CSS变量 | Sass | Less |
|---|---|---|---|
| 变量 | ✓ | ✓ | ✓ |
| 嵌套 | ✗ | ✓ | ✓ |
| 混合宏 | ✗ | ✓ | ✓ |
| 函数 | ✗ | ✓ | ✓ |
| 继承 | ✗ | ✓ | ✓ |
| 动态修改 | ✓ | ✗ | ✗ |
| 浏览器原生 | ✓ | ✗ | ✗ |
6.2 使用场景
CSS变量适用场景:
- 需要动态修改样式
- 运行时主题切换
- 响应式设计中的断点调整
- 与JavaScript交互
预处理器适用场景:
- 复杂的CSS结构
- 需要代码复用
- 大型项目中的样式管理
- 需要高级功能(如函数、循环)
6.3 混合使用
scss
// Sass变量(编译时)
$primary-color: #007bff;
// CSS变量(运行时)
:root {
--primary-color: #{$primary-color};
--font-size: 16px;
}
// 使用Sass混合宏
@mixin button-style($bg-color) {
background-color: $bg-color;
color: white;
padding: 12px 24px;
border: none;
border-radius: 4px;
}
// 使用CSS变量
.button {
@include button-style(var(--primary-color));
font-size: var(--font-size);
}
七、实战案例
7.1 设计系统变量
scss
// _variables.scss
// 颜色系统
$color-primary: #007bff;
$color-secondary: #6c757d;
$color-success: #28a745;
$color-danger: #dc3545;
$color-warning: #ffc107;
$color-info: #17a2b8;
// 字体系统
$font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
$font-size-base: 16px;
$font-size-sm: 14px;
$font-size-lg: 18px;
// 间距系统
$spacing-xs: 4px;
$spacing-sm: 8px;
$spacing-md: 16px;
$spacing-lg: 24px;
$spacing-xl: 32px;
// 断点系统
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;
scss
// _mixins.scss
// 响应式断点
@mixin respond-to($breakpoint) {
@if $breakpoint == 'sm' {
@media (min-width: $breakpoint-sm) { @content; }
} @else if $breakpoint == 'md' {
@media (min-width: $breakpoint-md) { @content; }
} @else if $breakpoint == 'lg' {
@media (min-width: $breakpoint-lg) { @content; }
} @else if $breakpoint == 'xl' {
@media (min-width: $breakpoint-xl) { @content; }
}
}
// Flex布局
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
@mixin flex-between {
display: flex;
justify-content: space-between;
align-items: center;
}
// 文本截断
@mixin text-truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
// 清除浮动
@mixin clearfix {
&::after {
content: '';
display: table;
clear: both;
}
}
7.2 主题切换系统
scss
// _themes.scss
// 浅色主题
:root,
[data-theme="light"] {
--theme-bg: #ffffff;
--theme-text: #333333;
--theme-primary: #007bff;
--theme-border: #dddddd;
--theme-shadow: rgba(0, 0, 0, 0.1);
}
// 深色主题
[data-theme="dark"] {
--theme-bg: #1a1a1a;
--theme-text: #ffffff;
--theme-primary: #4dabf7;
--theme-border: #444444;
--theme-shadow: rgba(0, 0, 0, 0.3);
}
// 主题变量使用
body {
background-color: var(--theme-bg);
color: var(--theme-text);
}
.card {
background-color: var(--theme-bg);
border: 1px solid var(--theme-border);
box-shadow: 0 2px 4px var(--theme-shadow);
}
.button {
background-color: var(--theme-primary);
}
7.3 组件库变量系统
scss
// _components.scss
// 按钮组件
.button {
// 基础变量
--button-bg: var(--theme-primary);
--button-text: white;
--button-padding: #{$spacing-sm} #{$spacing-md};
--button-radius: 4px;
--button-font-size: #{$font-size-base};
// 样式
background-color: var(--button-bg);
color: var(--button-text);
padding: var(--button-padding);
border-radius: var(--button-radius);
font-size: var(--button-font-size);
border: none;
cursor: pointer;
// 变体
&--secondary {
--button-bg: var(--theme-secondary);
}
&--danger {
--button-bg: var(--theme-danger);
}
&--small {
--button-padding: #{$spacing-xs} #{$spacing-sm};
--button-font-size: #{$font-size-sm};
}
&--large {
--button-padding: #{$spacing-md} #{$spacing-lg};
--button-font-size: #{$font-size-lg};
}
}
八、最佳实践总结
8.1 CSS变量最佳实践
css
/* 1. 使用:root定义全局变量 */
:root {
--primary-color: #007bff;
--spacing-unit: 8px;
}
/* 2. 使用有意义的变量名 */
:root {
--color-primary: #007bff; /* 颜色 */
--font-size-base: 16px; /* 字体大小 */
--spacing-md: 16px; /* 间距 */
}
/* 3. 使用默认值 */
.box {
color: var(--primary-color, #007bff);
}
/* 4. 避免过度使用变量 */
/* 不推荐 */
.box {
color: var(--color);
font-size: var(--size);
margin: var(--margin);
}
/* 推荐 */
.box {
color: var(--primary-color);
font-size: var(--font-size-base);
margin: var(--spacing-md);
}
8.2 Sass/Less最佳实践
scss
// 1. 使用部分文件(partials)
// _variables.scss
// _mixins.scss
// _components.scss
// 2. 使用嵌套但避免过度嵌套
.nav {
.nav-item {
.nav-link {
// 最多3层嵌套
}
}
}
// 3. 使用混合宏复用代码
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
// 4. 使用函数计算值
@function calculate-rem($px) {
@return $px / 16 * 1rem;
}
8.3 构建工具集成
json
// package.json
{
"scripts": {
"build:css": "sass src/scss:dist/css --style compressed",
"watch:css": "sass --watch src/scss:dist/css",
"prefix:css": "postcss dist/css/*.css --use autoprefixer --dir dist/css",
"build": "npm run build:css && npm run prefix:css"
}
}
总结
| 工具 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| CSS变量 | 原生支持、动态修改、运行时更新 | 功能有限 | 主题切换、响应式设计 |
| Sass | 功能强大、代码复用、成熟生态 | 需要编译 | 大型项目、组件库 |
| Less | 简单易学、JavaScript集成 | 功能相对较少 | 中小型项目 |
| PostCSS | 插件丰富、未来语法、性能优化 | 配置复杂 | 所有项目 |
CSS变量和预处理器是现代CSS开发的重要工具。建议根据项目需求选择合适的工具,可以混合使用以获得最佳效果。
九、常见面试题与易错点
9.1 面试题精选
题目1:请解释CSS变量和Sass变量的区别,并说明各自的使用场景。
参考答案:
- CSS变量:运行时变量,可以在JavaScript中动态修改,支持回退值,浏览器原生支持
- Sass变量:编译时变量,编译后消失,不支持动态修改,需要编译工具
- 使用场景:CSS变量适合主题切换、响应式设计;Sass变量适合设计系统、代码复用
题目2 :以下代码中,.box 的颜色是什么?
css
:root {
--primary-color: blue;
}
.box {
--primary-color: red;
color: var(--primary-color);
}
答案 :红色,因为CSS变量遵循就近原则,.box 中定义的变量会覆盖 :root 中的变量
题目3:什么是CSS预处理器?常见的CSS预处理器有哪些?
参考答案:
- CSS预处理器是一种脚本语言,扩展了CSS的功能,增加了变量、嵌套、混合宏、函数等特性
- 常见的CSS预处理器:Sass、Less、Stylus
- 优点:代码复用、模块化、可维护性高
- 缺点:需要编译、学习成本、调试困难
9.2 易错点总结
| 易错点 | 错误示例 | 正确写法 | 原因 |
|---|---|---|---|
| CSS变量作用域错误 | 全局变量覆盖局部变量 | 使用局部变量时在元素上定义 | CSS变量遵循就近原则 |
| Sass变量未定义 | 使用未定义的变量 | 先定义变量再使用 | Sass变量需要先定义 |
| 混合宏参数错误 | 参数类型不匹配 | 使用默认值 | 混合宏参数需要正确类型 |
| 嵌套层级太深 | 超过3层嵌套 | 使用类选择器 | 深层嵌套影响性能和可读性 |
| 忘记编译Sass | 直接使用.scss文件 | 使用编译工具 | Sass需要编译成CSS |
9.3 调试技巧
Chrome DevTools 调试CSS变量:
- 打开开发者工具
- 选择元素
- 在Styles面板查看CSS变量
- 可以直接修改CSS变量值
- 使用Computed面板查看计算后的值
常用调试命令:
javascript
// 获取CSS变量值
const root = document.documentElement;
const primaryColor = getComputedStyle(root).getPropertyValue('--primary-color');
console.log(primaryColor);
// 设置CSS变量值
root.style.setProperty('--primary-color', 'red');
// 删除CSS变量
root.style.removeProperty('--primary-color');
十、浏览器兼容性参考
| 特性 | Chrome | Firefox | Safari | Edge | IE |
|---|---|---|---|---|---|
| CSS变量 | 49+ | 31+ | 9.1+ | 15+ | 不支持 |
| var() 函数 | 49+ | 31+ | 9.1+ | 15+ | 不支持 |
| Sass | 需要编译 | 需要编译 | 需要编译 | 需要编译 | 需要编译 |
| Less | 需要编译 | 需要编译 | 需要编译 | 需要编译 | 需要编译 |
| PostCSS | 需要编译 | 需要编译 | 需要编译 | 需要编译 | 需要编译 |
兼容性建议:
- 现代项目:优先使用CSS变量,结合Sass/Less进行代码组织
- 需要兼容IE:使用Sass/Less变量,避免使用CSS变量
- 使用PostCSS进行CSS转换和优化