Sass/SCSS 语法速查表 - Sass 常用语法与 Mixin 大全

当样式表开始出现大段重复声明,Sass 的价值就不在语法糖,而在于把「值」和「片段」抽出来:颜色与间距这类标量进变量与 Map,配值逻辑走函数,重复的声明序列收进 Mixin,需要复用的选择器块用 % 占位符配合 @extend。工具链上选 SCSS 而非缩进语法,因为它是 CSS 超集,老文件能直接改;模块加载则应当用 @use 替代 @import,重复加载同一文件会明显拖慢编译。表里按变量运算、Map 与颜色函数、嵌套、Mixin 与继承、函数循环、条件控制、模块引入分组。判断标准也很明确:如果改动只应该影响一处,就抽成变量或 Mixin;如果允许任意选择器复用,用 @extend;如果需要携带参数与逻辑,用 @mixin —— 三者混用前先想清楚扩展点会在编译产物里留下多少重复选择器。

Web 服务·共 40 条命令·最后更新 2026-07-21
sassscsscss

典型使用场景

面向维护一套中型设计系统或组件库样式的前端工程师:统一色板与间距刻度、消除重复的 flex 居中代码、让断点集中管理、避免选择器嵌套膨胀到不可维护。Sass 把这些变成语言层面的能力。本表覆盖变量与运算(含 !default 与插值)、Map 与颜色函数、嵌套与 @at-root、mixin 与 @extend 的取舍、函数与循环、条件与控制指令、以及模块化引入(@use / @forward 与已废弃的 @import)。需要建立的两个判断是:@extend 会让选择器组合爆炸并影响其它规则,通常优先用 mixin;@import 已被官方标记为废弃并在新版 Dart Sass 里逐步移除,新代码应该一律用 @use。

变量与运算 5

$primary: #6366f1
定义变量
color: $primary
使用变量
$primary: #6366f1 !default
默认值(已定义则不覆盖)
width: 100px + 50px
数值运算
content: "icon-#{$name}"
插值 #{}

Map 与颜色函数 8

$sizes: (small: 12px, large: 24px)
Map 变量
width: map-get($sizes, small)
获取 Map 值
map-keys($sizes)
所有键
map-merge($sizes, (medium: 16px))
合并 Map
color: darken(#6366f1, 10%)
加深颜色
color: lighten(#6366f1, 10%)
提亮颜色
color: mix(red, blue)
混合两种颜色
color: rgba(#6366f1, 0.5)
设置透明度

嵌套 4

nav { ul { margin: 0 } }
选择器嵌套
a { &:hover { color: red } }
伪类嵌套
.btn { &-primary { color: blue } }
父选择器引用(生成 .btn-primary)
.box { @at-root .inner { } }
跳出嵌套

Mixin 与继承 8

@mixin flex-center { display: flex; justify-content: center }
定义 Mixin
@include flex-center
使用 Mixin
@mixin responsive($breakpoint) { @media ... }
带参数的 Mixin
@mixin button { @content }
接收内容块
.btn { @include button { color: red } }
传入内容块
%message-box { border: 1px solid }
定义占位符选择器
@extend %message-box
继承占位符
.error { @extend %message-box }
继承样式

函数与循环 4

@function px-to-rem($px) { @return $px / 16 * 1rem }
自定义函数
@for $i from 1 through 3 { .col-#{$i} { } }
for 循环
@each $color in red, blue, green { .#{$color} { } }
each 循环
@while $i > 0 { .item-#{$i} { } $i: $i - 1 }
while 循环

条件与控制 5

@if $type == dark { background: black }
条件判断
@else if $type == light { background: white }
else if
@else { background: gray }
else
@warn "变量未定义"
警告输出
@error "参数错误"
错误输出(终止编译)

引入与模块化 6

@import "variables"
导入文件(老语法)
@use "variables" as *
使用模块(推荐)
@use "variables" as vars
带命名空间使用
@use "config" with ($primary: red)
配置模块的 !default 变量
@forward "variables"
转发模块
@import url("https://fonts.googleapis.com")
导入外部 CSS

参数矩阵

参数作用示例
$primary: #6366f1声明 Sass 变量,编译后消失,不会产生运行时 CSS 输出$primary: #6366f1
color: $primary在属性值里使用变量,是色板统一的基本用法color: $primary
$primary: #6366f1 !default仅在变量尚未被赋值时才生效,是库文件暴露可覆盖配置的惯用写法$primary: #6366f1 !default
width: 100px + 50px同类单位可直接相加;不同单位相加会报错,需用 calc 或先转换width: 100px + 50px
#{$name}插值:把变量嵌进选择器、属性名或字符串,是生成循环类名的前提content: "icon-#{$name}"
$sizes: (small: 12px, large: 24px)Map 存键值对,比一串平铺变量更利于按语义取值$sizes: (small: 12px, large: 24px)
map-get($sizes, small)按 key 取值;key 不存在时返回 null 而不是报错width: map-get($sizes, small)
map-keys($sizes)取出所有 key,可配合 @each 遍历整张 Mapmap-keys($sizes)
map-merge($sizes, (medium: 16px))合并 Map,用于在局部覆盖默认刻度而不改动原 Mapmap-merge($sizes, (medium: 16px))
darken / lighten按固定比例变暗/变亮;因为是线性调整而非感知均匀,视觉上常不如预期color: darken(#6366f1, 10%)
mix(red, blue)按比例混合两个颜色,生成中间色color: mix(red, blue)
rgba(#6366f1, 0.5)由色值加透明度生成 rgba,比手写两个色值更不易写错color: rgba(#6366f1, 0.5)
nav { ul { margin: 0 } }嵌套编译成后代选择器,让作用域化写法成立;过深嵌套会让选择器膨胀nav { ul { margin: 0 } }
&:hover& 代表父选择器,常用于伪类与伪元素a { &:hover { color: red } }
&-primary& 后直接拼接可生成同级新类名(如 .btn-primary),不必重复前缀.btn { &-primary { color: blue } }
@at-root跳出当前嵌套输出选择器,是引入第三方选择器或 BEM 结构时的必需品.box { @at-root .inner { } }
@mixin flex-center { ... }定义可复用的样式片段;不产生选择器,只在被 @include 时展开@mixin flex-center { display: flex; justify-content: center }
@include flex-center展开一个 mixin;带参数时在括号里传参@include flex-center
@mixin responsive($breakpoint) { @media ... }把 @media 封进 mixin,断点集中管理,避免各处硬编码尺寸@mixin responsive($breakpoint) { @media ... }
@mixin button { @content }用 @content 预留内容块,实现带自定义内容的复用片段@mixin button { @content }
@include button { color: red }给带 @content 的 mixin 传入内容块.btn { @include button { color: red } }
%message-box占位选择器,只定义样式不生成输出,供 @extend 复用%message-box { border: 1px solid }
@extend %message-box把占位样式并入当前选择器;会改变选择器组合,影响范围超出预期时优先改用 mixin.error { @extend %message-box }
@function px-to-rem($px) { @return ... }定义 Sass 函数,在样式值里调用,编译后函数消失@function px-to-rem($px) { @return $px / 16 * 1rem }
@for $i from 1 through 3按序号循环,配合插值生成 .col-1 .col-2 .col-3@for $i from 1 through 3 { .col-#{$i} { } }
@each $color in red, blue, green遍历列表或 Map 的键,批量生成同构规则@each $color in red, blue, green { .#{$color} { } }
@while $i > 0条件循环,写法更灵活也更容易写出死循环,工程里优先用 @for@while $i > 0 { .item-#{$i} { } $i: $i - 1 }
@if / @else if / @else在编译期做分支,用于按配置切换主题或尺寸@if $type == dark { background: black }
@warn打印警告但继续编译,适合提示未定义变量这类非致命问题@warn "变量未定义"
@error直接中止编译并给出消息,用于参数非法这类必须失败的情况@error "参数错误"
@use "variables"加载模块;命名空间隔离,变量需带前缀访问,是官方推荐写法@use "variables"
@use "variables" as *把模块成员并入当前作用域,接近旧 @import 的体验,但仅限此文件@use "variables" as *
@use "variables" as vars给模块起命名空间别名,访问时写 vars.$primary@use "variables" as vars
@use "config" with ($primary: red)带 !default 的变量可在加载时覆盖,是配置注入的正规做法@use "config" with ($primary: red)
@forward "variables"把本文件的成员转发给上层,让一个入口文件统一收口多个模块@forward "variables"
@import "variables"旧引入方式,全局作用域且重复引入会重复输出,已被官方废弃@import "variables"
@import url("https://fonts.googleapis.com")保留 CSS 原样输出,用于无法用 Sass 表达的第三方样式@import url("https://fonts.googleapis.com")

易错点与避坑指南

现象编译警告提示 @import 已废弃,未来版本会移除。

原因@import 仍是旧项目的主力引入方式;Dart Sass 已把多个 @import 合并为 @use。

处置新代码一律用 @use / @forward;存量项目按模块逐个迁移,一个文件一个模块地改。

现象同一份样式被打包了两遍,CSS 体积翻倍。

原因多个文件都 @import 了同一个模块,而 @import 没有命名空间隔离也没有去重效果。

处置改用 @use,模块只会被加载一次;多个入口文件用 @forward 收口。

现象@extend 之后某些不相干的规则也被改写了。

原因@extend 会把选择器组合进所有匹配处,嵌套深、占位选择器多时组合数量迅速膨胀。

处置把共享样式写成带参数的 mixin 用 @include;只在选择器结构稳定、影响面清晰时用 @extend。

现象darken 之后颜色看起来几乎没变,或者变了但达不到想要的对比度。

原因darken/lighten 是按固定比例做线性调整,与视觉感知不一致;需求往往是「与白底达到某对比度」。

处置改用 modern-color 的 color.adjust 并指定明度目标,或直接用设计系统里验证过的色阶变量。

现象变量明明在某处赋值了,其它地方却读到空值。

原因@use 的模块是命名空间隔离的,必须写 names.$var,直接引用 $var 会报未定义。

处置统一用 @use 里的命名空间访问;确需全局便利时用 as * 但只在该文件内使用。

现象覆盖默认值没生效,样式仍是库里的原值。

原因!default 只在该变量「尚未被赋值」时生效;如果当前文件先赋值了变量,再 @use 就覆盖不了。

处置改用 @use "config" with ($primary: red) 在加载时注入,这是官方推荐的配置方式。

现象编译极慢,输出 CSS 里出现大量重复的选择器。

原因深层嵌套叠加 @extend,组合爆炸;另一常见原因是嵌套里写了选择器而不是声明块。

处置限制嵌套层数(通常不超过 3 层),共享样式改用 mixin,并用 sourcemap 定位重复来源。

现象编译报 "Undefined variable",但变量确实在某个文件里定义了。

原因文件加载顺序问题:变量在使用之后才被定义,Sass 按出现顺序求值。

处置把变量集中到单一入口文件并最先 @use;配合 @forward 让依赖顺序显式化。

排障路径

  1. 1定位已废弃指令的位置

    grep -rn "@import" src --include="*.scss"

    逐个确认是 Sass 模块引入还是保留的 CSS 原样输出。

  2. 2统计混用 @use 与 @import 的文件

    grep -rln "@use" src --include="*.scss"

    与上一条结果对照,找出尚未迁移的模块。

  3. 3排查 @extend 的实际影响范围

    grep -rn "@extend" src --include="*.scss"

    每处 @extend 都要能说清它会命中哪些选择器。

  4. 4找出所有 !default 变量

    grep -rn "!default" src --include="*.scss"

    确认哪些变量允许被外部覆盖。

  5. 5检查深嵌套导致的重复规则

    grep -rn "^ *\(16,\)" src --include="*.scss"

    过深缩进往往对应过深的嵌套与选择器组合。

  6. 6确认硬编码色值是否已收敛到变量

    grep -rn "#[0-9a-fA-F]\{3,6\}" src --include="*.scss"

    散落的字面色值是主题切换失效的常见原因。

命令示例

带参数的 mixin 收敛媒体查询

@mixin responsive($breakpoint) { @media (max-width: $breakpoint) { @content; } } .card { @include responsive(768px) { display: block; } }

断点散落在十几个文件里,改一次要全局搜索替换。收进一个带参 mixin 后,断点只在定义处出现一次,其余地方全部走 @include。@content 让调用方决定块内容,这样 mixin 管「什么时候生效」,调用点管「生效时改什么」。

map 存设计 token,@use 带命名空间导入

$sizes: (small: 12px, large: 24px) @use "variables" as vars .btn { font-size: vars.$sizes__small; padding: map-get(vars.$sizes, small); }

旧式 @import 把变量铺进全局作用域,同名 $primary 在不同文件里互相覆盖,编译通过但结果不是你想要的;@use 的命名空间把每个模块的变量隔离开,重名也只是 vars.$primary 和 theme.$primary 之别。而且同一个模块 @use 多次只会执行一次,@import 多次则重复输出全部内容。

输出

.btn {
  font-size: 12px;
  padding: 12px;
}

用 !default 做可被外部覆盖的默认值

$primary: #6366f1 !default @use "config" with ($primary: red) .btn { color: $primary }

!default 的语义是「已定义则不覆盖」:只有当 $primary 尚未被赋值时才取右边的值。@use ... with (...) 会在模块被载入前注入配置值,专为这种场景设计。少了 !default,调用方就无法定制主题色,只能改源文件。

输出

.btn {
  color: red;
}

@at-root 跳出嵌套作用域

.theme-dark { color: white; @at-root .input { border-color: #444; } }

嵌套在 .theme-dark 里的 .input 默认会编译成 .theme-dark .input(后代选择器),如果本意是「无论在哪个主题下都用这个全局样式」,就必须用 @at-root 把它提到顶层。这是最容易写错、也最难一眼看出的 Sass 语义之一。

输出

.theme-dark {
  color: white;
}
.input {
  border-color: #444;
}

颜色工具函数统一调节主题色

$primary: #6366f1 .btn { background: $primary; color: white; } .btn:hover { background: darken($primary, 10%) } .btn:disabled { background: lighten($primary, 10%) }

把品牌色收敛成一个 $primary 后,hover、disabled、浅色背景都从它推导出来(darken / lighten / mix / rgba),换肤只改一行。注意 rgba($color, $alpha) 改的是透明度不是颜色本身;只想要半透明底色时用 rgba($primary, 0.5),会连同颜色的不透明度一起算。

输出

.btn:hover {
  background: #5046e0;
}

常见坑与注意事项

  • 继续用 @import 而不是 @use 是最常见的隐患:@import 全局共享作用域,同名 $primary、@mixin 会在后一个文件里静默覆盖前一个,编译不报错但产物颜色全变。迁移期先查 @import 数量,优先把共享变量文件改成 @use "variables" as * 或 as vars。
  • 用 @import 加载含 @use 的文件会报错,混用两套模块系统时构建失败的位置常常指向完全不相关的文件。看到 "This file is already loaded" 或 "Cannot find stylesheet to import" 之类的报错,先把该文件的 @import 换成 @use。
  • 颜色运算函数 darken / lighten / mix 在实现上做的是数值插值,不是感知亮度调节。#6366f1 darken 10% 视觉上不一定「更暗」,在黄色系上 lighten 常常看不出变化。设计稿对比明显时,改成手写具体色值或用 color.adjust 配合 $lightness。
  • 尺寸除法:Sass 里 10px / 2 的结果仍然是 10px(除法只在特定场景下生效),想算比例必须写成 math.div(10px, 2)。在旧版本里 / 被当作分隔符,写错时编译能过但输出的是原值,样式直接不生效且无提示。
  • @error 会立刻终止编译,@warn 只打印提示继续跑。把 @error 写在公共 mixin 的参数校验里时,某个页面传入非法参数会让整个站点构建失败——把这类校验留给确实无法降级的场景,其余用 @warn 保证可构建。
  • @extend 占位符选择器会合并选择器、扩大匹配范围,用在通用类(如 %message-box 被 .error 和 .warning 同时继承)时可能把不该命中的元素也拉进来,且每加一个 @extend 全样式表都要重编译,大工程里明显拖慢构建。优先用 mixin 组合。

提示

  • SCSS 语法(.scss)兼容 CSS,Sass 语法(.sass)用缩进,推荐用 SCSS。
  • @use 是 Sass 推荐的新模块化方式,比 @import 更清晰。
  • Mixin 适合复用代码块,% 占位符适合复用样式(不生成多余代码)。
  • 用 @use "sass:math" 后调用 math.div($a, $b),除法不再是斜杠写法,避免与旧语法混淆。
  • map.get($config, "primary", $fallback) 提供默认值键,比先 map.has-key 再取值更简洁。
  • 编译时加 --no-source-map 减小产物体积;调试定位问题需要映射时再单独生成一次。

常见问题

@import 和 @use 都能引文件,新项目该用哪个?

新项目用 @use,它是推荐的模块化方式,加载后命名空间清晰。@use "variables" as vars 之后变量要写 vars.$primary;@use "variables" as * 则省略前缀,等价于旧行为。想覆盖模块里的默认值(那些声明了 !default 的变量),用 @use "config" with ($primary: red)。老代码里的 @import "variables" 属于旧语法,全局作用域污染容易出命名冲突,新代码别再用。它还有另一个正当用途:@import url("https://fonts.googleapis.com") 引入外部 CSS。

Mixin、@extend 和 % 占位符该怎么分工?

Mixin 复用「声明块」,用来输出属性和值:@mixin flex-center { display: flex; justify-content: center } 定义后 @include flex-center 调用;需要调用方塞内容进去就加 @content,再由 .btn { @include button { color: red } } 传入。% 占位符复用「样式组」,%message-box { border: 1px solid } 定义后 @extend %message-box 继承,它自身不会生成任何 CSS 选择器。简单说:一段属性用 Mixin,一组选择器共用的样式用 % 加 @extend。

要生成一组有规律的类名,循环和插值怎么配合?

循环负责产出次数,插值 #{} 负责把变量拼进选择器。@for $i from 1 through 3 { .col-#{$i} { } } 生成 .col-1 到 .col-3;@each $color in red, blue, green { .#{$color} { } } 按值遍历;@while $i > 0 { .item-#{$i} { } $i: $i - 1 } 在条件不满足时停止。插值同样用于属性值:content: "icon-#{$name}" 会生成 icon-xxx 字面量,而不是把 #{$name} 当普通字符输出。

响应式断点不想到处复制粘贴,怎么抽象?

把断点做成带参数的 Mixin:@mixin responsive($breakpoint) { @media ... } 定义一次,调用时把具体值传进去,媒体查询条件写在 Mixin 体内。Map 可以集中管理断点:$sizes: (small: 12px, large: 24px) 配合 map-get($sizes, small) 取值,需要合并新档位用 map-merge($sizes, (medium: 16px))。嵌套跳出用 @at-root:.box { @at-root .inner { } } 让 .inner 输出到顶层而不是编译成 .box .inner。

SCSS 里的数值运算和颜色函数,实际能省多少事?

数值可以直接参与运算:width: 100px + 50px 编译成 150px,自定义函数也常用,如 @function px-to-rem($px) { @return $px / 16 * 1rem }。颜色侧有 darken(#6366f1, 10%)、lighten(#6366f1, 10%)、mix(red, blue) 做混色,rgba(#6366f1, 0.5) 直接给主色加透明度,不必手写 rgba 值。调试时 @warn "变量未定义" 只提示继续编译,@error "参数错误" 则直接中止编译,适合给 Mixin 的必填参数做校验。

官方参考来源

下方为命令对应的官方权威文档,供你核对最新用法与深入查阅。

由 巧匠 维护

公开更新于 2026年7月21日,内容持续校对官方文档。

联系我们

命令或描述有误?提交反馈、商务合作或产品建议都可发送邮件给我们。

联系我们