跳到主要内容

CSS 预处理器

问题

什么是 CSS 预处理器?Sass 和 Less 有什么区别?PostCSS 是什么?CSS Modules 怎么用?

答案

预处理器概述

CSS 预处理器扩展了 CSS 语法,增加变量、嵌套、混入、函数等编程能力,编译后生成标准 CSS。

Sass / SCSS

Sass 是最流行的 CSS 预处理器,SCSS 是其兼容 CSS 语法的扩展格式。

变量

variables.scss
$primary: #3b82f6;
$font-size-base: 16px;
$spacing: 8px;

.button {
background: $primary;
font-size: $font-size-base;
padding: $spacing * 2; // 16px
}

嵌套

nesting.scss
.nav {
display: flex;

&__item { // .nav__item(BEM)
padding: 8px 16px;

&--active { // .nav__item--active
color: $primary;
}

&:hover { // .nav__item:hover
background: #f5f5f5;
}
}

// 父选择器引用
.dark & { // .dark .nav
background: #333;
}
}

Mixin(混入)

mixins.scss
// 定义 Mixin
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}

@mixin text-ellipsis($lines: 1) {
@if $lines == 1 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} @else {
display: -webkit-box;
-webkit-line-clamp: $lines;
-webkit-box-orient: vertical;
overflow: hidden;
}
}

@mixin respond-to($breakpoint) {
@if $breakpoint == 'mobile' {
@media (max-width: 767px) { @content; }
} @else if $breakpoint == 'tablet' {
@media (min-width: 768px) and (max-width: 1023px) { @content; }
} @else if $breakpoint == 'desktop' {
@media (min-width: 1024px) { @content; }
}
}

// 使用
.card {
@include flex-center;
}

.title {
@include text-ellipsis(2); // 两行省略
}

.sidebar {
width: 100%;
@include respond-to('desktop') {
width: 300px;
}
}

继承(@extend)

%base-button {  // 占位符选择器
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}

.btn-primary {
@extend %base-button;
background: $primary;
color: white;
}

.btn-secondary {
@extend %base-button;
background: #e5e7eb;
color: #333;
}

函数与运算

// 内置函数
$color: darken($primary, 10%); // 加深
$color: lighten($primary, 10%); // 减淡
$color: rgba($primary, 0.5); // 透明度
$color: mix(#f00, #00f, 50%); // 混合

// 自定义函数
@function rem($px, $base: 16) {
@return #{$px / $base}rem;
}

.box {
font-size: rem(14); // 0.875rem
padding: rem(24); // 1.5rem
}

模块系统

@use(推荐,替代 @import)
// _variables.scss
$primary: #3b82f6;

// _mixins.scss
@mixin flex-center { ... }

// main.scss
@use 'variables' as vars;
@use 'mixins';

.button {
background: vars.$primary;
@include mixins.flex-center;
}

Less

Less 语法与 Sass 类似,但使用 @ 作为变量前缀:

style.less
@primary: #3b82f6;
@spacing: 8px;

.button {
background: @primary;
padding: @spacing * 2;

&:hover {
background: darken(@primary, 10%);
}
}

// Mixin
.flex-center() {
display: flex;
justify-content: center;
align-items: center;
}

.card {
.flex-center();
}

Sass vs Less

特性Sass/SCSSLess
变量前缀$@
语法.scss(CSS 兼容)/ .sass(缩进).less
编译Dart Sass(官方推荐)less.js
条件/循环@if@for@each@while有限支持
模块系统@use@forward无标准模块
生态更丰富Ant Design 使用
社区Bootstrap、Tailwind 等Ant Design
选择建议

新项目推荐 Sass(SCSS),生态更完善。如果使用 Ant Design 则 Less 更方便。 但在 2024 年,很多项目已经转向 PostCSS + CSS 变量原子化 CSS(Tailwind)。

PostCSS

PostCSS 不是预处理器,而是 CSS 转换工具——通过插件对 CSS 进行处理。

常用插件

插件说明
Autoprefixer自动添加浏览器前缀
postcss-preset-env使用未来 CSS 特性(如嵌套)
postcss-px-to-viewportpx 转 vw 移动端适配
postcss-pxtorempx 转 rem
cssnanoCSS 压缩优化
postcss-nestingCSS 原生嵌套语法
postcss.config.ts
export default {
plugins: {
autoprefixer: {},
'postcss-preset-env': {
stage: 2,
features: {
'nesting-rules': true,
},
},
cssnano: process.env.NODE_ENV === 'production' ? {} : false,
},
};

CSS Modules

CSS Modules 自动生成唯一的类名,解决样式冲突问题:

Button.module.css
.button {
background: #3b82f6;
color: white;
padding: 8px 16px;
}

.primary {
background: #3b82f6;
}

.large {
font-size: 18px;
padding: 12px 24px;
}
Button.tsx
import styles from './Button.module.css';

function Button() {
return (
<button className={`${styles.button} ${styles.primary}`}>
Click me
</button>
);
}

编译后:<button class="Button_button_x7sj2 Button_primary_a3kd1">


常见面试问题

Q1: Sass 和 Less 有什么区别?

答案

核心区别:

  • 变量:Sass 用 $,Less 用 @
  • 编程能力:Sass 更强(完善的条件、循环、模块系统)
  • 编译:Sass 用 Dart Sass,Less 用 JavaScript
  • 生态:Sass 更主流(Bootstrap、Tailwind),Less 在 Ant Design 中使用

Q2: 为什么需要 CSS 预处理器?

答案

CSS 本身缺少编程能力,预处理器解决了:

  1. 代码复用:变量、Mixin 避免重复
  2. 可维护性:嵌套、模块化组织代码
  3. 计算能力:函数、运算减少硬编码
  4. 代码组织@use/@import 拆分文件

但随着 CSS 原生支持了变量(var())、嵌套(&)和 calc(),预处理器的必要性正在降低。

Q3: PostCSS 和 Sass 是什么关系?

答案

SassPostCSS
类型预处理器CSS 工具平台
工作方式有自己的语法通过插件处理标准 CSS
能力固定的特性集取决于配置的插件
关系可以和 PostCSS 配合可以替代预处理器的部分功能

常见搭配:Sass 写源码 → PostCSS(Autoprefixer + cssnano)后处理。

Q4: CSS Modules 和 Scoped CSS 有什么区别?

答案

特性CSS ModulesVue Scoped CSS
实现方式生成唯一类名添加 data-v-xxx 属性
框架通用(React/Vue)Vue 专属
选择器影响类名完全隔离通过属性选择器作用域限制
使用方式styles.className<style scoped>
深度穿透无需:deep() / ::v-deep

Q5: @import@use 有什么区别?

答案

特性@import(已弃用)@use
作用域全局(变量、Mixin全局可见)命名空间隔离
重复加载每次 @import 都会加载只加载一次
访问方式直接使用namespace.$variable
私有成员不支持$_private_ 开头
// ❌ @import(弃用)
@import 'variables';
color: $primary; // 全局可见

// ✅ @use(推荐)
@use 'variables' as vars;
color: vars.$primary; // 命名空间隔离

Q6: Autoprefixer 的原理是什么?

答案

Autoprefixer 是 PostCSS 插件,根据 Can I Use 数据库和项目的 browserslist 配置,自动为 CSS 添加或移除浏览器前缀:

/* 输入 */
.box {
display: flex;
user-select: none;
}

/* 输出 */
.box {
display: -webkit-flex;
display: flex;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}

配合 package.json.browserslistrc 中的配置:

{
"browserslist": ["> 1%", "last 2 versions", "not dead"]
}

Q7: Sass 中 @extend@mixin 有什么区别?

答案

特性@extend@mixin
参数不支持支持
编译结果合并选择器复制代码
输出体积较小(选择器合并)较大
使用场景继承相同样式带参数的复用
// @extend → 合并选择器
.btn-primary, .btn-secondary {
padding: 8px 16px;
border-radius: 4px;
}

// @mixin → 复制代码
.card { display: flex; justify-content: center; align-items: center; }
.modal { display: flex; justify-content: center; align-items: center; }

推荐:有参数用 @mixin,纯复用用 @extend(配合占位符 %)。

相关链接