基本介绍

CSS 预处理语言会提供一套基于 CSS 的增强语法,通过预处理技术编译为普通的 CSS 语言即可正常被浏览器解析。

CSS 预处理器的出现,解决了如下的问题:

  • 代码组织:通过嵌套、模块化和文件引入等功能,使 CSS 代码结构更加清晰,便于管理和维护。
  • 变量和函数:支持自定义变量和函数,增强代码的可重用性和一致性。
  • 代码简洁:通过简洁的语法结构和内置函数,减少代码冗余,提高开发效率。
  • 易于扩展:可以通过插件系统扩展预处理器的功能,方便地添加新特性。

目前常见的 CSS 预处理器有三个:

  • Sass
  • Less
  • Stylus

Sass

Sass 是最早出现的 CSS 预处理器,出现的时间为 2006 年,该预处理器有两种语法格式:

缩进式语法(2006 年):

$primary-color: #4CAF50
 
.container
	background-color: $primary-color
	padding: 20px
 
  .title
    font-size: 24px
    color: white

类 CSS 语法(2009 年):

$primary-color: #4CAF50;
 
.container {
  background-color: $primary-color;
  padding: 20px;
 
  .title {
    font-size: 24px;
    color: white;
  }
}

Sass 提供了很多丰富的功能,例如声明变量、嵌套、混合、继承、函数等,另外 Sass 还有强大的社区支持以及丰富的插件资源,因此 Sass 比较适合大型项目以及团队协作。

Less

Less 也是一个比较流行的 CSS 预处理器,该预处理器是在 2009 年出现的,借鉴了 Sass 的长处,并在此基础上兼容 CSS 语法,让开发者开发起来更加的得心应手

@primary-color: #4CAF50;
    
.container {
  background-color: @primary-color;
  padding: 20px;
 
  .title {
    font-size: 24px;
    color: white;
  }
}

早期的 Sass 只有缩进式语法,所以 Less 的出现降低了开发者的学习成本(Less 兼容原生 CSS 语法),相较于 Sass,Less 学习曲线平滑、语法简单,但是编程功能相比 Sass 要弱一些,并且插件和社区也没有 Sass 那么强大,Less 的出现反而让 Sass 出现了第二版语法(类 CSS 语法)

Stylus

Stylus 是一种灵活且强大的 CSS 预处理器,其语法非常简洁,具有很高的自定义性。Stylus 支持多种语法风格,包括缩进式和类 CSS 语法。提供了丰富的功能,如变量、嵌套、混合、条件语句、循环等。相较于 Sass 和 Less,Stylus 的社区规模较小,但仍有不少开发者喜欢其简洁灵活的特点。

primary-color = #4CAF50
 
.container
  background-color primary-color
  padding 20px
 
  .title
    font-size 24px
    color white

Sass 快速入门

Sass 最早是由 Hampton Catlin 开发于 2006 年,并于 2007 年首次发布。

在最初的时候, Sass 采用的是缩进敏感语法,文件的扩展名为 .sass,编写完毕之后,需要通过基于 Ruby 的 Ruby Sass 编译器编译为普通的 CSS。因此在最早期的时候,如果想要使用 Sass,需要安装 Ruby 环境。

为什么早期选择使用 Ruby 呢?这和当时的 Web 开发大环境有关系,在 2006 - 2010 年左右,当时 Web 服务器端开发就特别流行使用基于 Ruby 的 Web 框架 Ruby on Rails。早期的 Github、Twitter 等一开始都是使用 Ruby。

到了 2009 年, Less 的出现给 Sass 带来竞争压力,因为 Less 是基于原生 CSS 语法进行扩展,使用者没有什么学习压力,于是 Natalie Weizenbaum 和 Chris Eppstein 为 Sass 引入了新的类 CSS 语法,也是基于原生的 CSS 进行语法扩展,文件的后缀名为 .scss。虽然文件的后缀以及语法更新了,但是功能上仍然支持之前 Sass 所支持的所有功能,再加上 Sass 本身插件及社区就比 Less 强大,因此 Sass 重新变为了主流。

编译器方面,随着社区的发展和技术的进步,Sass 已经不在局限于 Ruby,目前已经有多种语言实现了 Sass 的编译器:

  • Dart Sass:由 Sass 官方团队维护,使用 Dart 语言编写。它是目前推荐的 Sass 编译器,因为它是最新的、功能最全的实现。
  • LibSass:使用 C/C++ 编写的 Sass 编译器,它的性能优于 Ruby 版本。LibSass 有多个绑定,例如 Node Sass(Node.js 绑定)和 SassC(C 绑定)。
  • Ruby Sass:最早的 Ruby 实现,已被官方废弃,并建议迁移到 Dart Sass。

现在主要使用 Dart Sass 和 LibSass:

  • Dart Sass 发布成了纯 JavaScript(Dart 编译为 JS)的 npm 包 sass
  • LibSass 是作为 npm 包 node-sass 的本地扩展发布的

虽然实现方式不一样,但是他们暴露出的 JavaScript API 是完全一致的。也就是说,无论使用哪一种都可以完成一个将 Sass 编译成 CSS 代码的 JavaScript 模块,在这个模块中,不管引用 sass 还是 node-sass,都可以使用完全一样的 API 来编写。

Sass 快速上手示例,创建一个新的项目目录 sass-demo,使用 pnpm init 初始化后安装 Sass 依赖:

pnpm add sass -D

写入如下的 Scss 代码:

$primary-color: #4caf50;
 
.container {
    background-color: $primary-color;
    padding: 20px;
 
    .title {
        font-size: 24px;
        color: white;
    }
}

接下来遇到了一个问题:编译。可以使用 Sass 提供的 compile 方法进行编译:

// 读取 scss 文件
// 调用 sass 依赖提供的 complie 进行文件的编译
// 最终在 dist 目录下面新生成一个 index.css(编译后的文件)
 
const sass = require('sass'); // 做 scss 文件编译的
const path = require('path'); // 处理路径相关的
const fs = require('fs'); // 处理文件读写相关的
 
// 定义一下输入和输出的文件路径
const scssPath = path.resolve("src", "index.scss");
const cssDir = "dist"; // 之后编译的 index.css 要存储的目录名
const cssPath = path.resolve(cssDir, "index.css");
 
// 编译
const result = sass.compile(scssPath);
console.log(result.css);
 
// 将编译后的字符串写入到文件里面
if (!fs.existsSync(cssDir)) {
    fs.mkdirSync(cssDir);
}
fs.writeFileSync(cssPath, result.css);

也可以使用 sass 命令行编译:

# 全局安装 CLI 包
npm install -g sass
 
# 基本语法,输入文件和输出文件都表示文件相对或绝对路径
sass 输入文件 输出文件
sass 输入文件:输出文件
sass 输入文件1:输出文件1 输入文件2:输出文件2 输入文件3:输出文件3
 
# 将当前目录的 index.scss 文件编译成 index.css 并放到当前目录
sass index.scss index.css
 
# 也可以写成:
sass index.scss:index.css
 
# 同时处理多个文件,使用空格分隔
sass index.scss:index.css index1.scss:index1.css
 
# 处理目录,将 styles 目录全部 sass/scss 编译到 public/css 目录中
sass styles:public/css

也可以直接安装 VSCode Sass 相关的插件来做编译,例如 scss-to-css

在现在使用广泛的是通过 Webpack 构建的项目中,使用 sass-loader 来自动化编译 Sass 代码,这个 sass-loader 包就是使用了 Sass 暴露的 JavaScript API 来完成编译的,它可以依赖 sass 包,也可以依赖 node-sass 包。