FORMA

语法基础:变量、嵌套与运算

本文覆盖 Sass 日常使用最频繁的四类语法:变量嵌套运算注释。概念与安装见 Sass 简介;复用机制(Mixin/继承)见 复用机制;模块与控制流见 模块与控制流

一、变量

Sass 变量存储可复用值(颜色、字号、间距等),使用 $ 声明,编译为 CSS 中的具体值。模块化组织见 模块与控制流

1. 基本语法

scss
// 声明变量
$primary-color: #3498db;
$font-size-base: 16px;
$border-radius: 4px;

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

编译后的 CSS:

css
.button {
  background-color: #3498db;
  font-size: 16px;
  border-radius: 4px;
}

2. 作用域

  • 全局变量:在选择器外部声明,可在任何地方使用。
  • 局部变量:在选择器或函数内部声明,仅在该作用域内有效。
scss
$global-color: #333; // 全局变量

.container {
  $local-color: red; // 局部变量(仅在此块内有效)
  color: $local-color;
  background: $global-color; // ✅ 可访问全局变量
}

// 强制修改全局变量(慎用)
.content {
  $global-color: black !global; // 将局部修改提升为全局
  color: $global-color; // 使用修改后的全局变量
}

// 错误:$local-color 在此处未定义
// .footer { color: $local-color; }

最佳实践:避免滥用 !global,通常通过变量文件(如 _variables.scss)统一管理全局变量,保持作用域清晰。

3. 默认值 !default

!default 用于为变量指定默认值:如果该变量之前已经被赋值,则使用已有值;否则使用默认值。常用于可配置的组件库。

scss
// _theme.scss
$theme-color: blue !default;

// main.scss(@use 时通过 with 覆盖)
@use "theme" with (
  $theme-color: red,
);

.button {
  background: theme.$theme-color;
}

4. 数据类型

Sass 支持 6 种主要数据类型:

类型示例说明
数字(Numbers)10, 10px, 10%, 10deg可带或不带单位
字符串(Strings)"微软雅黑", sans-serif, 'Helvetica'可有引号或无引号
布尔值(Booleans)true, false用于条件判断
颜色(Colors)#FF00FF, rgb(255,0,255), hsl(360,50%,50%)多种表示法
列表(Lists)10px 20px 30px(空格分隔)
Arial, Helvetica, sans-serif(逗号分隔)
类似数组
Map 映射(key1: value1, key2: value2)键值对集合
空值(Null)null未定义或缺失值
scss
$font-stack: "Helvetica", sans-serif; // 列表
$breakpoints: (
  // Map
  small: 576px,
  medium: 768px,
  large: 992px
);
$border-style: solid; // 字符串
$is-dark-mode: false; // 布尔值

5. 变量插值 #{}

在某些位置(如选择器名称、属性名称、字符串中),直接使用 $变量名 无效,必须使用插值语法 #{$变量名} 将变量的值嵌入为字符串的一部分。

scss
$dir: "left";
$version: "v1";
$font-name: "Roboto";

// 1. 用在属性名中
margin-#{$dir}: 10px; // 编译为:margin-left: 10px;

// 2. 用在选择器名称中(动态构造类名)
.alert-#{$version} {
  color: red;
}
// 编译后:.alert-v1 { color: red; }

// 3. 用在字符串中(如 @font-face 的 url)
@font-face {
  font-family: #{$font-name};
  src: url("/fonts/#{$font-name}.woff2");
}

// 4. 用在注释中
/* 当前版本: #{$version} */

注意:插值 #{} 不能用于数字运算,它只是纯文本替换。例如 #{$size}px 可以拼接带单位的数字,但 $size 本身必须是数字。

变量小结

  • 声明:$name: value;;插值:#{$name} 用于选择器名、属性名等。
  • 作用域:局部优先;慎用 !global
  • 配置:!default 配合 @use ... with (...)

二、嵌套

Sass 嵌套用于表达 DOM 层级,减少重复父选择器。建议不超过 3 层,避免生成过长选择器。现代原生 CSS 嵌套&)在浏览器中已可用,语法与 SCSS 相近,详见本文第四节。

1. 选择器嵌套

scss
.nav {
  ul {
    margin: 0;
    li {
      display: inline-block;
      a {
        color: $primary-color;
      }
    }
  }
}

编译后的 CSS:

css
.nav ul {
  margin: 0;
}
.nav ul li {
  display: inline-block;
}
.nav ul li a {
  color: #3498db;
}

最佳实践:嵌套层级不超过 3 层,避免生成过于冗长的 CSS 选择器,保持性能。

2. 父选择器引用 &

& 符号表示嵌套规则的外层父选择器,用于在嵌套内部引用父级选择器的名称,特别适用于伪类、伪元素、BEM 修饰符等场景。

scss
.button {
  background: blue;

  &:hover {
    // 编译为 .button:hover
    background: darkblue;
  }

  &::before {
    // 编译为 .button::before
    content: "";
  }

  &--primary {
    // BEM 命名法,编译为 .button--primary
    background: green;
  }
}

多个 & 连用(表示并列的多个父级选择器):

scss
.side {
  .widget & {
    // 编译为 .widget .side
    color: red;
  }
}

注意& 展开时是完整解析过的父选择器序列(包含空格),而不是简单的字符串拼接。

3. 属性嵌套

对于具有相同命名空间(如 border-*font-*margin-* 等)的属性,可以使用属性嵌套来简化编写。

scss
.box {
  border: {
    top: 1px solid red;
    bottom: 2px dashed blue;
  }
}
// 编译为:
// .box { border-top: 1px solid red; border-bottom: 2px dashed blue; }

也支持缩写与展开混用:

scss
font: {
  family: "Arial";
  size: 16px;
  weight: bold;
}
// 编译为:font-family: "Arial"; font-size: 16px; font-weight: bold;

4. @at-root 指令

@at-root 指令可以让当前选择器跳出所有祖先选择器的嵌套,直接回到根选择器层级。这在重构代码或需要生成独立于父级的规则时非常有用。

scss
.parent {
  color: blue;

  @at-root .child {
    color: red; // 编译为独立的 .child 选择器,而非 .parent .child
  }
}

编译结果:

css
.parent {
  color: blue;
}
.child {
  color: red;
}

带参数 with / without(高级用法):

scss
@at-root (without: all) { ... }   // 跳出所有层级(包括媒体查询等)
@at-root (with: media) { ... }    // 仅保留媒体查询层,跳出其他

典型应用场景:生成工具类(全局样式)、将部分样式从深层嵌套中“解放”出来、更好地配合 BEM 或 utility-first 框架。

嵌套小结

特性语法用途
选择器嵌套父 { 子 { } }表达层级,减少重复
父选择器引用 &&:hover&--modifier伪类、伪元素、BEM 修饰符
属性嵌套border: { top: ...; }简化同一命名空间的属性
@at-root@at-root .selector跳出当前嵌套,回到根层级

合理利用嵌套可以让样式更清晰;层级宜浅,并关注编译后选择器权重。

三、运算

Sass 支持数学、颜色与字符串运算;需注意数据类型、单位兼容性及除法应使用 sass:mathmath.div()

1. 数学运算

Sass 支持标准的加(+)、减(-)、乘(*)运算,以及除法(推荐使用 math.div() 函数)。

scss
@use "sass:math";

$base: 16px;

.box {
  width: 100% / 3; // 算术除法(仅当 / 在表达式中有意义时,不推荐)
  padding: $base * 2; // 32px
  margin: $base + 10px; // 26px
  line-height: math.div(24px, $base); // 1.5(无单位纯数字)
}

除法运算的特别注意

  • 旧语法:使用 / 作为除法运算符(如 width: 100% / 3;)。
  • 问题:在 CSS 原生语法中,/ 有多种含义(如 font: 12px/14px 表示字号/行高)。为消除歧义,Dart Sass 自 2.0 起已将孤立 / 标记为过时
  • 推荐做法:始终使用 math.div() 函数执行除法,避免使用 /
scss
// ❌ 不推荐(会触发警告)
$ratio: 100% / 3;

// ✅ 推荐
@use "sass:math";
$ratio: math.div(100%, 3);

2. 单位规则

Sass 的数学运算遵循“单位代数”规则:

  • 相同单位的量可以加减乘除,结果保留单位(如 10px + 5px = 15px)。
  • 不同单位的量在加减时会尝试转换,但若转换不合理(如 10px + 2em),Sass 会抛出编译错误,因为 em 相对于父元素的 px 值在编译期无法确定。
  • 乘法:单位会相乘(如 5in * 5in = 25in²),但 CSS 不支持平方英寸单位,通常应避免。
  • 推荐做法:在进行复杂计算前,先用 math.div() 剥离单位,得到纯数字,计算完后再恢复所需单位。
scss
@use "sass:math";

$value-with-unit: 24px;
$unitless: math.div($value-with-unit, 1px); // 24(无单位)

3. 颜色运算

Sass 支持对颜色值进行通道运算(RGB 每个通道分别计算)。注意:颜色运算不如 color 模块的函数精确,推荐使用内置颜色函数。

scss
$base-color: #036; // 相当于 rgb(0, 51, 102)

.darken {
  // 颜色通道相加:rgb(0+34, 51+34, 102+34) = rgb(34,85,136) → #225588
  background: $base-color + #222;
}

更常用的颜色调整方式(推荐):

scss
@use "sass:color";

.lighten {
  background: color.scale($base-color, $lightness: 20%);
}

4. 字符串运算

使用 + 运算符可以拼接字符串。注意:如果第一个操作数是带引号的字符串,结果也会带引号;否则结果无引号。

scss
$prefix: "icon-";

.icon {
  &::before {
    content: $prefix + "home"; // 输出 "icon-home"
  }
}

$font-family: "Helvetica" + ", " + Arial; // 结果为 "Helvetica, Arial"(自动补引号)

插值替代:在更复杂的字符串构建中,可以使用 #{} 插值。

运算小结

运算类型注意事项
数学运算除法使用 math.div();避免直接使用 /;相同单位可运算,不同单位加减需谨慎
单位规则乘积会产生复合单位,通常应避免;复杂运算先剥离单位
颜色运算通道加减,但推荐使用 color 模块函数
字符串运算使用 + 拼接;引号继承规则需留意

四、注释与原生 CSS 嵌套

1. 注释语法

Sass 支持三种注释语法,区别在于是否被保留到编译后的 CSS 文件中。

注释语法说明编译后是否保留
/* 内容 */标准 CSS 多行注释✅ 保留
// 内容单行注释(Sass 独有)❌ 不保留
/*! 内容 */重要注释(通常用于版权声明)✅ 保留(即使压缩模式下也会保留)
scss
// 以下是主题色变量——此注释在编译后会消失
$primary: #3498db;

/* 模块化CSS样式 */
.button {
  background: $primary;
}

/*! 版权声明:© 2026 MyCompany */

编译后的 CSS:

css
/* 模块化CSS样式 */
.button {
  background: #3498db;
}

/*! 版权声明:© 2026 MyCompany */

使用建议

  • 调试阶段可使用 // 注释辅助说明,不影响输出。
  • 需要保留在 CSS 中的说明(如模块说明、许可证)使用 /* ... */
  • 版权等重要声明使用 /*! ... */,确保即使开启 --style=compressed 也不会被移除。

2. 与原生 CSS 嵌套的关系

CSS 嵌套选择器 已在主流浏览器中实现(具体版本见 MDN 兼容性表)。语法与 SCSS 嵌套相似,但不包含 Sass 的变量、混入、控制指令等编译期能力。

相同点:& 父级引用

原生 CSS 也支持使用 & 符号引用父选择器,用法与 Sass 基本一致。

css
/* 原生 CSS 嵌套 */
.button {
  background: blue;
  &:hover {
    background: darkblue;
  }
}

主要限制与差异

特性Sass 嵌套原生 CSS 嵌套
选择器拼接方式默认使用空格后结合(后代选择器)同 Sass(空格表示后代)
串联选择器(如 .a.b可写作 &.b同样支持 &.b
嵌套深度无语法上限(工程上建议控制在较浅层级)无语法上限;过深选择器会增加匹配成本
@media 等规则内嵌套支持支持(见 MDN 嵌套与 at-rule 说明)
& 后直接跟类名支持(如 &.active支持
& 后跟复杂选择器(如 & > .child支持支持
后代嵌套(子规则以类型/类开头).parent { .child { } }.parent .child同左(见 MDN 嵌套规则)
对无效选择器的错误提示编译时报错浏览器解析时忽略无效规则

实际开发建议

  • 需要变量、混入、@use 模块等:继续使用 SCSS 编译为普通 CSS,与目标浏览器是否支持原生嵌套无关。
  • 仅使用嵌套、且目标环境已支持原生嵌套:可直接写 CSS 嵌套;发布前对照 MDN 兼容性表与项目最低浏览器要求。
  • 通用建议:控制嵌套深度,避免选择器过长;需要拼接父选择器时使用 &(与规范一致)。

总结

  • 注释:根据需要选择合适的语法,/*! */ 用于版权声明,// 仅开发使用。
  • 嵌套:在需编译链路的项目中 SCSS 嵌套仍常用;若仅面向现代浏览器,可评估 原生 CSS 嵌套 是否满足需求。
  • 变量与运算是 Sass 最基础的两块能力,配合 模块与控制流 中的内置函数可完成绝大多数样式计算。

参考文献

资料说明
Sass:Variables变量与作用域(英文)
Sass:Interpolation#{} 插值
Sass:Nesting嵌套规则(英文)
Sass:Operators运算符
Sass:sass:mathmath.div 等
Sass:Comments注释语法
MDN:CSS 嵌套原生嵌套

Series

sass

4 / 4