Learn X in Y minutes 仓库实战:Sass/SCSS 速览指南——从变量、控制指令到 Mixin 与模块化

原创2026-10-09 16:18:551,906 阅读
文章标签:文档教程

Learn X in Y minutes 仓库实战:Sass/SCSS 速览指南——从变量、控制指令到 Mixin 与模块化

Sass 是 CSS 的扩展语言,为样式表引入变量、嵌套、Mixin、继承等编程能力,帮助开发者写出可维护、DRY(Don't Repeat Yourself)的代码。本文以 learnxinyminutes-docs 仓库中的 sass.md 速览教程为主体,逐节拆解其核心语法并给出完整的编译前后对照,同时结合仓库的 README.md 与 CONTRIBUTING.md 说明本教程在“代码即文档”项目中的定位与质量规范。读完本文,你将掌握 Sass/SCSS 从变量、控制指令、Mixin、函数、继承、嵌套到模块化组织(Partials/Imports)与数学运算的完整实战用法。

本仓库中的 Sass 教程定位

learnxinyminutes-docs 是一个以“可运行的带注释代码”形式呈现编程语言速览教程的开源仓库,README 中将其描述为 Whirlwind tours of popular languages, presented as valid, commented code。这意味着 sass.md 的主体就是一段可以直接被 Sass 编译器处理的 .scss 代码,每一段代码都配有编译后的 CSS 输出,读者可以边读边在本地编译验证。

仓库同时提供了配套的质量保障脚本:lint/frontmatter.py 负责校验每个 Markdown 文档头部 YAML 元数据的合法性与字段类型(name、filename、contributors、translators 等),lint/encoding.sh 则检查所有 .md 文件必须为 UTF-8/US-ASCII 且不带 BOM。这意味着你在本仓库看到的所有教程文档(包括 Sass 教程及其 zh-cn/sass.md、de/sass.md、es/sass.md、pt-br/sass.md 等多语言翻译)都遵循统一的编码与元数据规范,可以直接作为学习材料。

Sass 与 SCSS:两种语法形态

Sass 提供两种可选的语法:

  • SCSS:与 CSS 语法完全一致(花括号 {} 加分号 ;),只是在其上叠加了 Sass 的全部扩展特性,对已有 CSS3 经验的开发者迁移成本最低;
  • Sass(缩进语法):原始语法,使用缩进替代花括号与分号,更简洁但需要重新适应。

本教程全程使用 SCSS 编写。需要特别说明的是,Sass 并不是提供新的样式属性,而是提供更高效编写与维护 CSS 的工具——如果你已熟悉 CSS3,很快就能上手。仓库中另有独立的 css.md 教程讲述 CSS 本身的规则、选择器与属性,可与本教程互为补充。

注释:单行删除,多行保留

Sass 中两类注释的编译行为截然不同:

// 单行注释在 Sass 编译为 CSS 时会被删除。

/* 多行注释会被保留。 */

实战中,// 适合写仅供开发阶段参考的内部说明(编译产物中不出现),/* */ 则适合写需要保留在最终 CSS 中的版权声明或对外注释。这一点与 CSS 自身只有 /* */ 一种注释形态(见 css.md)不同,是 Sass 带来的第一处便利。

变量:一处修改,全局生效

使用 $ 符号声明变量,可存储颜色、字体栈等任何 CSS 值:

$primary-color: #A3A4FF;
$secondary-color: #51527F;
$body-font: 'Roboto', sans-serif;

body {
	background-color: $primary-color;
	color: $secondary-color;
	font-family: $body-font;
}

编译结果为:

body {
	background-color: #A3A4FF;
	color: #51527F;
	font-family: 'Roboto', sans-serif;
}

变量让“改一处、处处生效”成为可能,比在样式表中逐处查找替换颜色值要可维护得多。这是 Sass 解决“重复自己”问题的最基础手段。

控制指令:让编译过程可编程

Sass 允许使用 @if、@else、@for、@while 和 @each 控制代码向 CSS 的编译过程。

@if / @else

$debug: true !default;

@mixin debugmode {
	@if $debug {
		@debug "Debug mode enabled";

		display: inline-block;
	}
	@else {
		display: none;
	}
}

.info {
	@include debugmode;
}

当 $debug 为 true 时 .info 显示,为 false 时隐藏。注意两点:$debug: true !default; 中的 !default 意味着该变量仅在未被赋值时使用默认值,便于被外部配置覆盖;@debug 会把调试信息输出到命令行,是排查 SCSS 变量值的好工具。

.info {
	display: inline-block;
}

@for:区间循环

@for 遍历一个数值区间,有两种形式:through 包含末值,to 止步于末值之前。

@for $c from 1 to 4 {
	div:nth-of-type(#{$c}) {
		left: ($c - 1) * 900 / 3;
	}
}

@for $c from 1 through 3 {
	.myclass-#{$c} {
		color: rgb($c * 255 / 3, $c * 255 / 3, $c * 255 / 3);
	}
}

编译为:

div:nth-of-type(1) {
	left: 0;
}

div:nth-of-type(2) {
	left: 300;
}

div:nth-of-type(3) {
	left: 600;
}

.myclass-1 {
	color: #555555;
}

.myclass-2 {
	color: #aaaaaa;
}

.myclass-3 {
	color: white;
// SASS automatically converts #FFFFFF to white
}

两个细节值得注意:#{$c} 是插值语法,把变量嵌入选择器名或属性值;to 4 只生成 1、2、3,而 through 3 生成 1、2、3,二者在末值语义上不同。同时可以看到,Sass 会自动把 #FFFFFF 归一化为 white。

@while:条件循环

$columns: 4;
$column-width: 80px;

@while $columns > 0 {
	.col-#{$columns} {
		width: $column-width;
		left: $column-width * ($columns - 1);
	}

	$columns: $columns - 1;
}

输出:

.col-4 {
	width: 80px;
	left: 240px;
}

.col-3 {
	width: 80px;
	left: 160px;
}

.col-2 {
	width: 80px;
	left: 80px;
}

.col-1 {
	width: 80px;
	left: 0px;
}

@while 循环体内必须显式修改循环变量(这里是 $columns: $columns - 1;),否则将造成死循环——这是与 @for 最本质的区别。

@each:遍历列表

@each 类似 @for,但遍历的是列表而不是数值。Sass 列表以空格作为分隔符声明:

$social-links: facebook twitter linkedin reddit;

.social-links {
	@each $sm in $social-links {
		.icon-#{$sm} {
			background-image: url("images/#{$sm}.png");
		}
	}
}

输出:

.social-links .icon-facebook {
	background-image: url("images/facebook.png");
}

.social-links .icon-twitter {
	background-image: url("images/twitter.png");
}

.social-links .icon-linkedin {
	background-image: url("images/linkedin.png");
}

.social-links .icon-reddit {
	background-image: url("images/reddit.png");
}

这是生成一组同类图标样式的典型模式:数据(列表)驱动样式生成,杜绝手写重复代码。

Mixin:可复用样式块

当同一段代码被多个元素使用时,可以存入 Mixin。用 @mixin 加名称定义,用 @include 加名称调用:

@mixin center {
	display: block;
	margin-left: auto;
	margin-right: auto;
	left: 0;
	right: 0;
}

div {
	@include center;
	background-color: $primary-color;
}

编译为:

div {
	display: block;
	margin-left: auto;
	margin-right: auto;
	left: 0;
	right: 0;
	background-color: #A3A4FF;
}

Mixin 还可以带参数,作为“简写属性”使用:

@mixin size($width, $height) {
	width: $width;
	height: $height;
}

.rectangle {
	@include size(100px, 60px);
}

.square {
	@include size(40px, 40px);
}

编译为:

.rectangle {
  width: 100px;
  height: 60px;
}

.square {
  width: 40px;
  height: 40px;
}

参数化 Mixin 让“同一套规则、不同取值”的重复样式只写一次逻辑,调用时只需传值。

函数:内置函数与自定义函数

Sass 提供大量内置函数,按名称调用并传入参数即可:

body {
  width: round(10.25px);
}

.footer {
  background-color: fade_out(#000000, 0.25);
}

编译为:

body {
  width: 10px;
}

.footer {
  background-color: rgba(0, 0, 0, 0.75);
}

round() 负责四舍五入,fade_out() 调整透明度并把十六进制颜色转换为 rgba() 形式。

也可以使用 @function 自定义函数。Mixin 与函数的选择原则是:Mixin 擅长生成 CSS 规则,函数擅长返回计算值,例如计算百分比:

@function calculate-percentage($target-size, $parent-size) {
  @return $target-size / $parent-size * 100%;
}

$main-content: calculate-percentage(600px, 960px);

.main-content {
  width: $main-content;
}

.sidebar {
  width: calculate-percentage(300px, 960px);
}

编译为:

.main-content {
  width: 62.5%;
}

.sidebar {
  width: 31.25%;
}

函数把“取目标尺寸与父尺寸的百分比”这一逻辑抽象为可复用单元,后续任何需要百分比的地方都可以直接调用。

@extend 继承:共享基础样式

@extend 让一个选择器继承另一个选择器的全部属性,是共享基础样式的另一种方式:

.display {
	@include size(5em, 5em);
	border: 5px solid $secondary-color;
}

.display-success {
	@extend .display;
	border-color: #22df56;
}

编译为:

.display, .display-success {
  width: 5em;
  height: 5em;
  border: 5px solid #51527F;
}

.display-success {
  border-color: #22df56;
}

相比 Mixin,@extend 的优势在于编译产物的体积:Sass 会把共享基础样式的所有选择器合并成一个选择器组,而用 Mixin 则会在每个调用处重复展开 width、height、border 等属性,虽然不影响工作流,却会给编译后的 CSS 文件带来不必要的冗余。

嵌套与 & 父选择器

Sass 允许选择器嵌套选择器,同时 & 会被替换为父选择器,天然适配伪类嵌套:

ul {
	list-style-type: none;
	margin-top: 2em;

	li {
		background-color: red;

		&:hover {
		  background-color: blue;
		}

		a {
		  color: white;
		}
	}
}

编译为:

ul {
  list-style-type: none;
  margin-top: 2em;
}

ul li {
  background-color: red;
}

ul li:hover {
  background-color: blue;
}

ul li a {
  color: white;
}

注意嵌套深度的取舍:过度嵌套会让代码更难维护,社区最佳实践建议嵌套不超过 3 层。&:hover 展开为 ul li:hover,正是 & 的典型用法。

Partials 与 @import:模块化组织

Sass 允许创建 partial 文件来模块化代码,partial 文件名以下划线开头(如 _reset.css),且不会被单独编译成 CSS 文件。例如把如下重置样式放入名为 _reset.css 的文件:

html,
body,
ul,
ol {
  margin: 0;
  padding: 0;
}

再用 @import 引入。Sass 的 @import 与传统 CSS @import 有本质区别:传统 CSS 的 @import 会发起一次额外的 HTTP 请求去抓取文件,而 Sass 是在编译期把被导入文件与当前代码合并:

@import 'reset';

body {
  font-size: 16px;
  font-family: Helvetica, Arial, Sans-serif;
}

编译为:

html, body, ul, ol {
  margin: 0;
  padding: 0;
}

body {
  font-size: 16px;
  font-family: Helvetica, Arial, Sans-serif;
}

注意导入时省略 _ 前缀与扩展名('reset' 即对应 _reset.css),这是 Sass partial 的约定。模块化之后,每个文件职责单一,最终通过一个入口文件组合输出。

Placeholder Selectors:仅供继承的占位符

如果某个样式块只服务于 @extend,不希望它出现在编译后的 CSS 中,可以用占位符选择器——以 % 开头而非 . 或 #:

%content-window {
  font-size: 14px;
  padding: 10px;
  color: #000;
  border-radius: 4px;
}

.message-window {
  @extend %content-window;
  background-color: #0000ff;
}

编译为:

.message-window {
  font-size: 14px;
  padding: 10px;
  color: #000;
  border-radius: 4px;
}

.message-window {
  background-color: #0000ff;
}

可以看到,%content-window 本身没有出现在编译产物中,只有被继承的 .message-window 拿到了全部基础属性——占位符是“只做基类、不产样式”的理想工具。

数学运算:直接计算栅格

Sass 提供 +、-、*、/、% 运算符,可直接在样式文件中计算数值,避免手工计算。下面是一个经典的两栏布局示例:

$content-area: 960px;
$main-content: 600px;
$sidebar-content: 300px;

$main-size: $main-content / $content-area * 100%;
$sidebar-size: $sidebar-content / $content-area * 100%;
$gutter: 100% - ($main-size + $sidebar-size);

body {
  width: 100%;
}

.main-content {
  width: $main-size;
}

.sidebar {
  width: $sidebar-size;
}

.gutter {
  width: $gutter;
}

编译为:

body {
  width: 100%;
}

.main-content {
  width: 62.5%;
}

.sidebar {
  width: 31.25%;
}

.gutter {
  width: 6.25%;
}

主内容 62.5% + 侧栏 31.25% + 沟槽 6.25% = 100%,全部由 Sass 在编译期算出。这种“用变量推导布局”的思路正是前文自定义函数 calculate-percentage() 的理想应用场景——把百分比计算封装成函数后,可被整个样式库复用。

命名小考:Sass 还是 SASS?

Sass 的名字是一个单词,并非首字母缩写。由于人们常误写成 “SASS”,语言作者便戏称其为 “Syntactically Awesome StyleSheets”(语法上极佳的样式表)。记住这一点,有助于你在文档、变量名与社区交流中使用正确的拼写。

实践与兼容性

如果想在浏览器中立即尝试 Sass,可以使用在线的 Sass playground(如 SassMeister),在设置中自由切换 Sass 缩进语法与 SCSS 语法,实时查看编译结果——本教程的全部代码都可以直接粘贴验证。

关于兼容性的核心结论是:Sass 可用于任何项目,只要你有把它编译为 CSS 的程序。编译产物是标准 CSS,因此最终决定样式能否生效的是目标浏览器对所用 CSS 特性的支持情况,而非 Sass 本身。上线前建议通过 CSS 兼容性查询工具(如 QuirksMode CSS 与 CanIUse)核对目标浏览器的支持矩阵——这一点在仓库配套的 css.md 教程中也有相应体现。

延伸阅读

本教程(sass.md)是 learnxinyminutes-docs 仓库中 Sass 主题的英文原文,仓库还收录了多种语言的翻译版本,包括 zh-cn/sass.md(简体中文)、de/sass.md、es/sass.md、pt-br/sass.md、ms/sass.md、vi/sass.md 与 cs/sass.md,方便对照阅读。若想系统了解 Sass 的完整语法与函数库,可进一步查阅 Sass 官方文档与社区教程(如 The Sass Way 提供的从入门到进阶的系列文章)。仓库内的 CONTRIBUTING.md 也给出了此类速览文档的编写规范(行宽、注释风格、frontmatter 元数据),如果你希望为 Sass 教程补充新示例或修正细节,可以参照该规范提交贡献。

登录后查看全文
learnxinyminutes-docs