CSS变量与预处理器

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变量:

  1. 打开开发者工具
  2. 选择元素
  3. 在Styles面板查看CSS变量
  4. 可以直接修改CSS变量值
  5. 使用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转换和优化
相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万4 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋4 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁4 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95274 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大4 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师4 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学4 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端