Learn X in Y minutes 仓库实战:Sass/SCSS 速览指南——从变量、控制指令到 Mixin 与模块化
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 教程补充新示例或修正细节,可以参照该规范提交贡献。