现代CSS-CSS预处理器对比
CSS预处理器是现代Web开发中不可或缺的工具,它们扩展了CSS的功能,引入了变量、嵌套、混合、函数等编程特性,使CSS更加强大、易于维护和复用。
本文将深入对比三大主流CSS预处理器:Sass、Less和Stylus,帮助你了解它们的特点、语法差异和使用场景,从而选择最适合项目的预处理器。
# 一、CSS预处理器概述
# 1.1 什么是CSS预处理器
CSS预处理器是一种用特定语法编写样式代码,然后编译成标准CSS的工具。它们提供了原生CSS不具备的功能:
- 变量(Variables):存储可复用的值
- 嵌套(Nesting):反映HTML结构的嵌套规则
- 混合(Mixins):复用样式代码块
- 函数(Functions):动态计算值
- 运算(Operations):数学运算和颜色操作
- 导入(Import):模块化组织代码
- 继承(Extend):继承其他选择器的样式
# 1.2 为什么需要预处理器
原生CSS的局限性:
- 没有变量,重复值需要手动维护
- 没有嵌套,选择器冗长重复
- 没有代码复用机制
- 缺少逻辑控制能力
预处理器的优势:
- 提高代码可维护性
- 增强代码复用性
- 支持模块化开发
- 提供编程能力
- 提升开发效率
# 1.3 三大预处理器简介
| 特性 | Sass | Less | Stylus |
|---|---|---|---|
| 发布时间 | 2006年 | 2009年 | 2010年 |
| 实现语言 | Ruby(Dart Sass用Dart) | JavaScript | JavaScript |
| 文件扩展名 | .sass / .scss | .less | .styl |
| 语法风格 | 严格/宽松 | 类CSS | 极简 |
| 社区规模 | 最大 | 中等 | 较小 |
| 学习曲线 | 中等 | 较低 | 中等 |
# 二、Sass详解
# 2.1 Sass简介
Sass(Syntactically Awesome Stylesheets)是最成熟、功能最强大的CSS预处理器,有两种语法:
- Sass语法(.sass):使用缩进,不需要分号和花括号
- SCSS语法(.scss):类似CSS,使用分号和花括号(推荐)
安装:
# 使用Dart Sass(推荐)
npm install -g sass
# 或在项目中安装
npm install --save-dev sass
# 2.2 Sass核心特性
# 变量
// 定义变量
$primary-color: #667eea;
$secondary-color: #764ba2;
$base-font-size: 16px;
$border-radius: 8px;
// 使用变量
.button {
background: $primary-color;
font-size: $base-font-size;
border-radius: $border-radius;
}
// 变量作用域
.container {
$local-padding: 20px; // 局部变量
padding: $local-padding;
}
// 默认变量(可被覆盖)
$base-spacing: 10px !default;
# 嵌套
// 选择器嵌套
.nav {
background: #333;
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
display: inline-block;
a {
color: white;
text-decoration: none;
padding: 10px 15px;
&:hover {
background: #555;
}
}
}
}
// 属性嵌套
.box {
border: {
style: solid;
width: 1px;
color: #ccc;
radius: 4px;
}
font: {
family: Arial, sans-serif;
size: 14px;
weight: bold;
}
}
// 父选择器引用 &
.button {
background: #667eea;
&:hover {
background: #5568d3;
}
&.active {
background: #4356be;
}
.theme-dark & {
background: #8891f2;
}
}
# 混合(Mixins)
// 定义混合
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
// 使用混合
.container {
@include flex-center;
}
// 带参数的混合
@mixin button-style($bg-color, $text-color: white) {
background: $bg-color;
color: $text-color;
padding: 10px 20px;
border-radius: 4px;
border: none;
cursor: pointer;
&:hover {
background: darken($bg-color, 10%);
}
}
.primary-btn {
@include button-style(#667eea);
}
.danger-btn {
@include button-style(#e74c3c, white);
}
// 可变参数
@mixin box-shadow($shadows...) {
box-shadow: $shadows;
}
.card {
@include box-shadow(
0 2px 4px rgba(0,0,0,0.1),
0 4px 8px rgba(0,0,0,0.1)
);
}
# 继承
// 定义基础样式
.button-base {
padding: 10px 20px;
border-radius: 4px;
border: none;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
}
// 继承
.primary-button {
@extend .button-base;
background: #667eea;
color: white;
}
.secondary-button {
@extend .button-base;
background: #ecf0f1;
color: #2c3e50;
}
// 占位符选择器(不会输出到CSS中)
%flex-center {
display: flex;
justify-content: center;
align-items: center;
}
.container {
@extend %flex-center;
}
.modal {
@extend %flex-center;
}
# 函数
// 内置函数
.element {
// 颜色函数
color: darken(#667eea, 20%);
background: lighten(#667eea, 20%);
border-color: saturate(#667eea, 30%);
// 数学函数
width: percentage(0.5); // 50%
padding: round(10.6px); // 11px
margin: ceil(10.1px); // 11px
}
// 自定义函数
@function calculate-rem($px-value, $base: 16px) {
@return ($px-value / $base) * 1rem;
}
.text {
font-size: calculate-rem(24px); // 1.5rem
}
// 复杂函数示例
@function strip-unit($number) {
@if type-of($number) == 'number' and not unitless($number) {
@return $number / ($number * 0 + 1);
}
@return $number;
}
# 控制指令
// @if 条件判断
@mixin theme-color($theme) {
@if $theme == 'light' {
background: white;
color: black;
} @else if $theme == 'dark' {
background: #2c3e50;
color: white;
} @else {
background: gray;
color: white;
}
}
.container {
@include theme-color('dark');
}
// @for 循环
@for $i from 1 through 4 {
.col-#{$i} {
width: percentage($i / 4);
}
}
// @each 遍历
$colors: (
primary: #667eea,
success: #2ecc71,
danger: #e74c3c,
warning: #f39c12
);
@each $name, $color in $colors {
.btn-#{$name} {
background: $color;
}
}
// @while 循环
$i: 1;
@while $i <= 3 {
.item-#{$i} {
width: 100px * $i;
}
$i: $i + 1;
}
# 模块化
// _variables.scss
$primary-color: #667eea;
$secondary-color: #764ba2;
// _mixins.scss
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
// main.scss
@import 'variables';
@import 'mixins';
// 或使用新的@use(推荐)
@use 'variables' as vars;
@use 'mixins';
.container {
background: vars.$primary-color;
@include mixins.flex-center;
}
# 三、Less详解
# 3.1 Less简介
Less(Leaner Style Sheets)是一个轻量级的CSS预处理器,语法更接近CSS,学习曲线较低。
安装:
# 全局安装
npm install -g less
# 项目中安装
npm install --save-dev less
# 3.2 Less核心特性
# 变量
// 定义变量
@primary-color: #667eea;
@secondary-color: #764ba2;
@base-font-size: 16px;
// 使用变量
.button {
background: @primary-color;
font-size: @base-font-size;
}
// 变量插值
@image-path: '../images';
.header {
background-image: url('@{image-path}/logo.png');
}
// 延迟加载(变量可以在定义前使用)
.container {
color: @text-color;
}
@text-color: #333;
# 嵌套
// 选择器嵌套(与Sass类似)
.nav {
background: #333;
ul {
list-style: none;
li {
display: inline-block;
a {
color: white;
&:hover {
color: #667eea;
}
}
}
}
}
// @ 规则嵌套
.component {
width: 300px;
@media (min-width: 768px) {
width: 600px;
}
@supports (display: grid) {
display: grid;
}
}
# 混合(Mixins)
// 定义混合
.flex-center {
display: flex;
justify-content: center;
align-items: center;
}
// 使用混合(带括号则不会输出到CSS)
.flex-center() {
display: flex;
justify-content: center;
align-items: center;
}
.container {
.flex-center();
}
// 带参数的混合
.button-style(@bg-color, @text-color: white) {
background: @bg-color;
color: @text-color;
padding: 10px 20px;
border-radius: 4px;
&:hover {
background: darken(@bg-color, 10%);
}
}
.primary-btn {
.button-style(#667eea);
}
// 带条件的混合
.mixin-if(@condition) when (@condition = true) {
color: red;
}
.mixin-if(@condition) when (@condition = false) {
color: blue;
}
.element {
.mixin-if(true);
}
# 继承
// Less使用:extend伪类
.button-base {
padding: 10px 20px;
border-radius: 4px;
border: none;
}
.primary-button {
&:extend(.button-base);
background: #667eea;
color: white;
}
// 扩展所有实例
.button-base {
padding: 10px 20px;
&:hover {
opacity: 0.8;
}
}
.primary-button {
&:extend(.button-base all);
background: #667eea;
}
# 运算
// 数学运算
.container {
width: 100% - 20px;
padding: 10px * 2;
margin: (10px + 5px) / 2;
}
// 颜色运算
@base-color: #667eea;
.element {
color: @base-color + #111;
background: @base-color * 0.8;
}
// 单位转换
.box {
width: 100px + 2em; // Less会尝试转换
}
# 函数
// 颜色函数
.element {
color: darken(#667eea, 20%);
background: lighten(#667eea, 20%);
border: 1px solid fade(#667eea, 50%);
}
// 数学函数
.box {
width: percentage(0.5); // 50%
height: round(10.6px); // 11px
padding: ceil(10.1px); // 11px
}
// 字符串函数
.element {
content: replace("Hello World", "World", "Less");
}
// 列表函数
@list: 1px, 2px, 3px;
.element {
padding: extract(@list, 1); // 1px
}
# 命名空间
// 定义命名空间
#theme {
.light {
background: white;
color: black;
}
.dark {
background: #2c3e50;
color: white;
}
}
// 使用命名空间
.container {
#theme.dark();
}
# 导入
// 导入Less文件
@import 'variables';
@import 'mixins';
// 导入CSS文件
@import (css) 'reset.css';
// 导入选项
@import (reference) 'bootstrap'; // 只引用不输出
@import (inline) 'custom.css'; // 直接插入内容
@import (less) 'style.css'; // 当作Less文件处理
@import (once) 'file.less'; // 只导入一次(默认)
@import (multiple) 'file.less'; // 允许多次导入
# 四、Stylus详解
# 4.1 Stylus简介
Stylus是最灵活的CSS预处理器,语法极简,可选的分号、冒号和花括号使代码更简洁。
安装:
# 全局安装
npm install -g stylus
# 项目中安装
npm install --save-dev stylus
# 4.2 Stylus核心特性
# 变量
// 定义变量(无需特殊符号)
primary-color = #667eea
secondary-color = #764ba2
base-font-size = 16px
// 使用变量
.button
background primary-color
font-size base-font-size
// 属性查找
.box
width 100px
height @width // 引用width的值
margin (@width / 2)
# 嵌套
// 选择器嵌套(无需花括号)
.nav
background #333
ul
list-style none
li
display inline-block
a
color white
text-decoration none
&:hover
color primary-color
// 父选择器引用
.button
background primary-color
&:hover
background darken(primary-color, 10%)
&.active
background darken(primary-color, 20%)
# 混合
// 定义混合(函数式)
flex-center()
display flex
justify-content center
align-items center
// 使用混合
.container
flex-center()
// 带参数的混合
button-style(bg-color, text-color = white)
background bg-color
color text-color
padding 10px 20px
border-radius 4px
&:hover
background darken(bg-color, 10%)
.primary-btn
button-style(#667eea)
// 块混合
with-border()
border 1px solid #ccc
{block}
.box
+with-border()
padding 10px
margin 5px
# 函数
// 定义函数
add(a, b)
a + b
.box
width add(100px, 50px)
// 颜色函数
.element
color darken(#667eea, 20%)
background lighten(#667eea, 20%)
border-color rgba(#667eea, 0.5)
// 内置函数
.container
width unit(100, 'px') // 100px
height percentage(0.5) // 50%
// 条件函数
color-type(color)
if lightness(color) > 50%
'light'
else
'dark'
.element
data-theme color-type(#667eea)
# 控制流
// 条件语句
theme-color(theme)
if theme == 'light'
background white
color black
else if theme == 'dark'
background #2c3e50
color white
else
background gray
color white
.container
theme-color('dark')
// 循环
for i in 1..4
.col-{i}
width (100% / 4 * i)
// 遍历
colors = {
primary: #667eea,
success: #2ecc71,
danger: #e74c3c
}
for name, color in colors
.btn-{name}
background color
# 插值
// 选择器插值
sides = top right bottom left
for side in sides
.margin-{side}
margin-{side} 10px
// 属性插值
vendor(prop, args)
-webkit-{prop} args
-moz-{prop} args
{prop} args
.box
vendor('border-radius', 5px)
# 透明混合
// 与CSS属性同名的混合会自动应用
border-radius(n)
-webkit-border-radius n
-moz-border-radius n
border-radius n
.box
border-radius 5px // 自动展开
// 块属性
border-radius(n)
-webkit-border-radius n
-moz-border-radius n
border-radius n
body
font 14px Arial, sans-serif
border-radius 5px
# 五、三者对比
# 5.1 语法对比
相同的样式,三种写法:
// Sass/SCSS
$primary-color: #667eea;
@mixin button-style {
padding: 10px 20px;
border-radius: 4px;
background: $primary-color;
&:hover {
background: darken($primary-color, 10%);
}
}
.button {
@include button-style;
}
// Less
@primary-color: #667eea;
.button-style() {
padding: 10px 20px;
border-radius: 4px;
background: @primary-color;
&:hover {
background: darken(@primary-color, 10%);
}
}
.button {
.button-style();
}
// Stylus
primary-color = #667eea
button-style()
padding 10px 20px
border-radius 4px
background primary-color
&:hover
background darken(primary-color, 10%)
.button
button-style()
# 5.2 功能对比
| 功能 | Sass | Less | Stylus |
|---|---|---|---|
| 变量 | $var | @var | var |
| 嵌套 | ✅ | ✅ | ✅ |
| 混合 | @mixin/@include | .mixin() | mixin() |
| 继承 | @extend | :extend | @extend |
| 导入 | @import/@use | @import | @import |
| 运算 | ✅ | ✅ | ✅ |
| 函数 | 丰富 | 丰富 | 丰富 |
| 条件 | @if/@else | when | if/else |
| 循环 | @for/@each/@while | 有限 | for |
| 内置函数 | 非常丰富 | 丰富 | 丰富 |
| JavaScript求值 | ❌ | ✅ | ✅ |
# 5.3 性能对比
编译速度(相对比较):
- Dart Sass:最快(使用Dart编写)
- Less:快(JavaScript实现)
- Stylus:较快(JavaScript实现)
- Ruby Sass:慢(已废弃)
生成的CSS质量:
- 三者生成的CSS质量相似
- Sass的
@extend优化最好 - 都支持压缩和Source Map
# 5.4 生态系统对比
| 方面 | Sass | Less | Stylus |
|---|---|---|---|
| 社区规模 | 最大 | 中等 | 较小 |
| 流行框架 | Bootstrap 4+, Bulma | Bootstrap 3 | Vuetify(部分) |
| 工具支持 | 最完善 | 完善 | 一般 |
| 插件数量 | 最多 | 较多 | 较少 |
| 学习资源 | 最丰富 | 丰富 | 一般 |
| 维护状态 | 活跃 | 活跃 | 较慢 |
# 六、选择建议
# 6.1 选择Sass的理由
✅ 适合场景:
- 大型项目或企业级应用
- 需要强大的功能和完整的生态
- 团队成员熟悉Sass
- 使用Bootstrap、Bulma等框架
✅ 优势:
- 功能最强大、最完善
- 社区最大、资源最丰富
- 工具链最成熟
- 文档最详细
❌ 劣势:
- 学习曲线相对较陡
- 语法较严格
推荐指数: ⭐⭐⭐⭐⭐
# 6.2 选择Less的理由
✅ 适合场景:
- 中小型项目
- 团队更熟悉JavaScript
- 需要在浏览器端编译
- 使用Ant Design等基于Less的UI库
✅ 优势:
- 语法最接近CSS,学习成本低
- 纯JavaScript实现,易集成
- 支持浏览器端编译
- 可以使用JavaScript表达式
❌ 劣势:
- 功能相对较少
- 社区规模较小
- 逻辑控制能力较弱
推荐指数: ⭐⭐⭐⭐
# 6.3 选择Stylus的理由
✅ 适合场景:
- 追求极简语法
- 小型项目或个人项目
- 喜欢灵活的语法风格
✅ 优势:
- 语法最灵活、最简洁
- 可选的符号(冒号、分号、花括号)
- 功能丰富
- 透明混合特性独特
❌ 劣势:
- 社区最小
- 学习资源较少
- 维护更新较慢
- 团队协作可能因语法灵活性产生分歧
推荐指数: ⭐⭐⭐
# 6.4 综合建议
项目选择流程:
是否使用了特定UI框架?
├─ 是 → 使用框架推荐的预处理器
│ (Bootstrap 4+用Sass, Ant Design用Less)
└─ 否 → 继续
团队是否已有偏好?
├─ 是 → 使用团队熟悉的
└─ 否 → 继续
项目规模和复杂度?
├─ 大型/复杂 → Sass (功能强大、生态完善)
├─ 中型 → Less (学习成本低、易上手)
└─ 小型/个人 → Stylus (语法简洁) 或 Sass
2024年推荐:
- 首选Sass:最成熟、最强大、社区最大
- 次选Less:学习成本低、JavaScript生态
- 可选Stylus:追求极简或特定需求
# 七、总结
CSS预处理器是现代前端开发的重要工具:
Sass/SCSS:
- 功能最强大、最完善
- 社区最大、生态最好
- 适合大型项目
- 推荐作为首选
Less:
- 语法接近CSS,易学习
- JavaScript生态集成好
- 适合中小型项目
- 适合JavaScript团队
Stylus:
- 语法最灵活简洁
- 功能丰富
- 适合小型项目或个人
- 社区相对较小
选择建议:
- 新项目首选Sass(特别是Dart Sass)
- 如果使用特定UI库,跟随其选择
- 考虑团队技术栈和偏好
- 评估项目规模和复杂度
无论选择哪个预处理器,都要:
- 遵循最佳实践
- 保持代码组织良好
- 合理使用功能
- 注意性能影响
- 编写可维护的代码
祝你变得更强!
编辑 (opens new window)
上次更新: 2025/11/20