写CSS的人都有这样的困扰:CSS是一门描述性的样式语言,语法简单,但写起来很繁琐。

第一,没有变量。同一个颜色(如主题色),在CSS里要写很多遍,如果要改颜色,得全局搜索替换,容易遗漏。同一个字体、同一个间距、同一个圆角,都是重复写。

第二,没有嵌套。CSS的选择器要一层层写,比如.nav .nav-item .nav-link,重复写父选择器,代码冗长,而且层级关系不直观。

第三,没有函数和运算。CSS不能做计算,比如宽度要根据某个值计算,只能手动算好写死。不能定义函数复用一段样式逻辑。

第四,代码重复多。很多样式是重复的,比如清除浮动、居中、圆角、阴影,每个地方都要写一遍,代码冗余,维护困难。

CSS预处理器(CSS Preprocessor)就是为了解决这些问题而生的。它扩展了CSS的语法,增加了变量、嵌套、混合(Mixin)、函数、继承、运算等编程语言的特性,让CSS写起来更高效、更简洁、更易维护。写好的预处理器代码,会被编译成标准的CSS,浏览器才能识别。

目前最流行的CSS预处理器有两个:Sass(Syntactically Awesome Style Sheets)和Less(Leaner Style Sheets)。两者功能类似,语法略有不同。今天就来介绍它们的基本用法,并做一个对比。

Sass入门

Sass是最早的CSS预处理器,诞生于2007年,用Ruby编写。Sass有两种语法格式:

  • .sass:缩进语法,用缩进代替大括号,用换行代替分号,简洁但和CSS差异大。
  • .scss:Sassy CSS,是CSS的超集,语法和CSS几乎一样,大括号和分号都保留,学习成本低。现在主流用的是SCSS语法。

变量

Sass用$符号定义变量:

// 定义变量
$primary-color: #3498db;
$font-size-base: 14px;
$spacing: 10px;

// 使用变量
.button {
  background-color: $primary-color;
  font-size: $font-size-base;
  padding: $spacing;
}

变量可以是颜色、数字、字符串、列表、映射等类型。变量有作用域,在选择器内定义的变量是局部变量,外部访问不到。可以用!global声明全局变量。

嵌套

Sass支持选择器嵌套,让层级关系更清晰:

// 普通嵌套
.nav {
  background: #333;
  
  .nav-item {
    display: inline-block;
    
    .nav-link {
      color: #fff;
      text-decoration: none;
      
      &:hover {
        color: $primary-color;
      }
    }
  }
}

&符号表示父选择器的引用,常用于伪类(:hover:active)和伪元素(::before::after)。

Sass还支持属性嵌套:

.button {
  font: {
    family: Arial, sans-serif;
    size: 14px;
    weight: bold;
  }
  border: {
    width: 1px;
    style: solid;
    color: #ccc;
  }
}

混合(Mixin)

Mixin是可复用的样式块,用@mixin定义,@include引用:

// 定义mixin
@mixin border-radius($radius: 5px) {
  -webkit-border-radius: $radius;
  -moz-border-radius: $radius;
  border-radius: $radius;
}

@mixin clearfix {
  &::after {
    content: "";
    display: table;
    clear: both;
  }
}

// 使用mixin
.button {
  @include border-radius(8px);
  @include clearfix;
}

Mixin可以传参数,参数可以有默认值。Mixin是Sass最强大的功能之一,能大幅减少重复代码。

继承(Extend)

继承让一个选择器可以继承另一个选择器的所有样式,用@extend

// 基础样式
.message {
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
}

// 继承基础样式
.success {
  @extend .message;
  border-color: green;
  background: #dff0d8;
}

.error {
  @extend .message;
  border-color: red;
  background: #f2dede;
}

继承和Mixin的区别:Mixin是把样式复制到引用处(会有重复代码),继承是把选择器合并(如.message, .success, .error共享样式),生成的CSS更简洁。但继承有一些限制(不能在@media中继承外部选择器),使用时要注意。

函数

Sass内置了很多函数,也可以自定义函数:

// 内置函数
.container {
  width: percentage(960px / 1200px); // 百分比
  color: lighten(#3498db, 20%); // 变亮
  background: darken(#fff, 5%); // 变暗
  padding: ceil(10.2px); // 向上取整
}

// 自定义函数
@function calculate-width($cols, $total: 12) {
  @return percentage($cols / $total);
}

.col-6 {
  width: calculate-width(6); // 50%
}

Sass的内置函数非常丰富,包括颜色函数(lighten、darken、mix、opacify等)、字符串函数、数字函数、列表函数、映射函数等,能满足各种复杂的样式计算需求。

运算

Sass支持数字运算:

$base-size: 16px;

.title {
  font-size: $base-size * 1.5; // 24px
  margin: $base-size / 2; // 8px
  padding: $base-size + 4px; // 20px
}

颜色也可以运算:

$color: #3498db;

.box {
  background: $color + #111; // 颜色相加
  border-color: $color * 1.2; // 颜色相乘
}

导入和模块化

Sass用@import导入其他Sass文件:

// 主文件style.scss
@import "variables";   // 导入_variables.scss
@import "mixins";      // 导入_mixins.scss
@import "base";        // 导入_base.scss
@import "components";  // 导入_components.scss

开头的Sass文件(如variables.scss)是局部文件,不会被单独编译成CSS,只会被导入。这样可以把样式模块化,分成变量、混合、基础样式、组件等不同文件,便于维护。

Less入门

Less诞生于2009年,受Sass启发,但用JavaScript编写,可以在浏览器端或Node.js环境编译。Less的语法和SCSS类似,也是CSS的超集,学习成本低。

变量

Less用@符号定义变量(和Sass的$不同):

// 定义变量
@primary-color: #3498db;
@font-size-base: 14px;

// 使用变量
.button {
  background-color: @primary-color;
  font-size: @font-size-base;
}

Less的变量是懒加载的,可以在使用之后定义,变量会提升到作用域顶部。

嵌套

Less的嵌套和Sass几乎一样:

.nav {
  background: #333;
  
  .nav-item {
    display: inline-block;
    
    .nav-link {
      color: #fff;
      
      &:hover {
        color: @primary-color;
      }
    }
  }
}

混合(Mixin)

Less的Mixin更简单,直接用类选择器定义,引用时直接写类名:

// 定义mixin(就是一个类选择器)
.border-radius(@radius: 5px) {
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
  border-radius: @radius;
}

.clearfix() {
  &::after {
    content: "";
    display: table;
    clear: both;
  }
}

// 使用mixin
.button {
  .border-radius(8px);
  .clearfix();
}

Less的Mixin不带括号时,定义的样式会输出到CSS中;带括号时,只作为mixin使用,不输出。Less的Mixin还支持条件判断(when关键字)和循环(recursive mixin)。

继承

Less的继承用&:extend()语法:

.message {
  padding: 10px;
  border: 1px solid #ccc;
}

.success {
  &:extend(.message);
  border-color: green;
}

Less的继承功能不如Sass强大,但基本够用。

函数

Less也有内置函数,包括颜色函数、数学函数、字符串函数等:

.container {
  width: percentage(960px / 1200px);
  color: lighten(#3498db, 20%);
  background: darken(#fff, 5%);
}

Less也可以用JavaScript表达式(在反引号中),但不推荐使用,因为可移植性差。

运算

Less的运算和Sass类似:

@base-size: 16px;

.title {
  font-size: @base-size * 1.5;
  margin: @base-size / 2;
}

导入

Less用@import导入文件:

@import "variables.less";
@import "mixins.less";
@import "base.less";

Less的导入比Sass灵活,可以导入CSS文件、可以设置导入选项(如@import (reference) "file.less"只引用不输出)。

Sass和Less对比

特性SassLess
诞生时间2007年2009年
编写语言Ruby(也有Node.js版本node-sass)JavaScript
变量符号$@
语法格式.sass(缩进)和.scss(CSS超集).less(CSS超集)
Mixin定义@mixin + @include类选择器 + 直接引用
继承@extend&:extend()
函数强大,内置函数丰富,支持自定义函数一般,内置函数较少
逻辑控制支持@if@for@each@while支持when条件,循环需用递归mixin
编译环境Ruby或Node.jsNode.js或浏览器端
社区和生态更成熟,Compass等框架丰富较大,Bootstrap用Less
学习曲线稍陡(功能多)平缓(语法简单)

怎么选?

两者功能类似,选哪个主要看项目需求和个人偏好:

  • 如果项目用Ruby on Rails,选Sass(Rails原生支持Sass)。
  • 如果项目用Bootstrap 3,选Less(Bootstrap 3用Less,Bootstrap 4改用Sass)。
  • 如果需要强大的函数和逻辑控制(如复杂的样式计算、循环生成样式),选Sass(Sass的函数和控制流更强大)。
  • 如果需要在浏览器端实时编译(如在线主题定制),选Less(Less可以在浏览器端用less.js编译)。
  • 如果团队熟悉JavaScript,选Less(Less用JS编写,生态和Node.js更契合)。
  • 如果是新项目,没有特殊约束,推荐Sass(更成熟、功能更强大、社区更活跃,而且Bootstrap 4已经改用Sass,说明Sass是趋势)。

我个人用的是Sass(SCSS语法),因为它的函数和控制流更强大,能处理复杂的样式需求,而且社区生态更成熟。

编译工具

写好的Sass/Less代码需要编译成CSS才能用。常用的编译工具有:

  • 命令行工具:Sass的sass命令,Less的lessc命令。适合简单项目。
  • 构建工具:Grunt、Gulp、Webpack等,配合对应的插件(grunt-sass、gulp-sass、sass-loader等),可以自动编译、压缩、加前缀。适合中大型项目。
  • 编辑器插件:Sublime Text、VS Code、WebStorm等编辑器都有Sass/Less插件,可以保存时自动编译。适合个人项目。
  • GUI工具:Koala、Prepros、CodeKit等图形化工具,拖拽文件就能编译,适合不熟悉命令行的开发者。

我个人用的是Gulp + gulp-sass,配合gulp-autoprefixer(自动加浏览器前缀)和gulp-clean-css(压缩CSS),构建流程自动化,效率很高。

总结

CSS预处理器是前端开发的必备工具,它让CSS写起来更高效、更简洁、更易维护。变量、嵌套、混合、函数、继承、运算这些特性,能大幅提升CSS的开发效率,减少重复代码。

Sass和Less是最流行的两个CSS预处理器,功能类似,语法略有不同。选哪个主要看项目需求和个人偏好,没有绝对的好坏。如果你还在用纯CSS写样式,建议试试CSS预处理器,它会改变你写CSS的方式,让你爱上写样式。