Sass/SCSS Cheatsheet - Sass Syntax & Mixin Reference

Once a stylesheet fills with repeated declarations, Sass earns its place by extracting values and fragments rather than by nicer syntax. Scales go into variables and Maps, colour maths into functions, repeated declaration sequences into mixins, and reusable selector blocks into % placeholders consumed by @extend. Pick SCSS over the indented syntax because SCSS is a superset of CSS and existing files convert cleanly, and load modules with @use rather than @import, since repeated imports measurably slow compilation. Sections cover variables and arithmetic, Maps and colour functions, nesting, mixins and inheritance, functions and loops, conditionals, and module imports. The judgement rule is simple: if a change should land in exactly one place, extract a variable or mixin; if any selector may reuse the block, reach for @extend; if the fragment needs parameters or logic, it has to be a mixin. Check how much duplicated selector output each choice leaves behind before combining them.

Web Services·40 commands·Last updated 2026-07-21
sassscsscss

Typical Use Case

For front-end engineers maintaining a mid-sized design system or component library: one palette, one spacing scale, breakpoints in one place, and no selector nesting past the point of review. Covers variables with !default, maps and colour functions, nesting with @at-root, mixin versus @extend, functions and loops, and modular loading with @use and @forward against the deprecated @import. Two judgements: @extend multiplies selector combinations, so prefer mixins, and use @use only.

Variables & Operations 5

$primary: #6366f1
Define a variable
color: $primary
Use a variable
$primary: #6366f1 !default
Default value (kept if already defined)
width: 100px + 50px
Numeric operations
content: "icon-#{$name}"
Interpolation with #{}

Maps & Color Functions 8

$sizes: (small: 12px, large: 24px)
Map variable
width: map-get($sizes, small)
Get a map value
map-keys($sizes)
All keys
map-merge($sizes, (medium: 16px))
Merge maps
color: darken(#6366f1, 10%)
Darken a color
color: lighten(#6366f1, 10%)
Lighten a color
color: mix(red, blue)
Mix two colors
color: rgba(#6366f1, 0.5)
Set opacity

Nesting 4

nav { ul { margin: 0 } }
Selector nesting
a { &:hover { color: red } }
Pseudo-class nesting
.btn { &-primary { color: blue } }
Parent selector reference (yields .btn-primary)
.box { @at-root .inner { } }
Break out of nesting (@at-root)

Mixins & Inheritance 8

@mixin flex-center { display: flex; justify-content: center }
Define a mixin
@include flex-center
Use a mixin
@mixin responsive($breakpoint) { @media ... }
Mixin with parameters
@mixin button { @content }
Mixin that accepts a content block
.btn { @include button { color: red } }
Pass a content block
%message-box { border: 1px solid }
Define a placeholder selector
@extend %message-box
Extend a placeholder
.error { @extend %message-box }
Inherit styles

Functions & Loops 4

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

Conditionals & Control 5

@if $type == dark { background: black }
Conditional (@if)
@else if $type == light { background: white }
@else if
@else { background: gray }
@else
@warn "Variable not defined"
Warning output
@error "Invalid argument"
Error output (stops compilation)

Imports & Modules 6

@import "variables"
Import a file (legacy syntax)
@use "variables" as *
Use a module (recommended)
@use "variables" as vars
Use with a namespace
@use "config" with ($primary: red)
Configure a module's !default vars
@forward "variables"
Forward a module
@import url("https://fonts.googleapis.com")
Import external CSS

Parameter matrix

ParameterEffectExample
$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")

Common pitfalls

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Troubleshooting

  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"

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

Command Examples

A parameterized mixin to centralize media queries

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

With breakpoints scattered across a dozen files, changing one means a project-wide search and replace. Folding them into a parameterized mixin leaves the value in exactly one place, and every other rule calls @include. @content lets the caller own the body, so the mixin decides when the rules apply and the call site decides what they do.

Store design tokens in a map, import with @use under a namespace

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

The old @import leaks variables into the global scope, so a $primary defined in two files silently overwrites the other: the build passes but the result is not what you meant. @use namespaces every module, so collisions are just vars.$primary versus theme.$primary. A module is also evaluated once no matter how many times you @use it, while repeated @import re-emits all of its content.

Output

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

Make defaults overridable with !default

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

!default means "do not override if already defined": the right-hand value is taken only when $primary has no value yet. @use "config" with (...) injects configuration before the module is evaluated, which is exactly what this pattern needs. Without !default the consumer cannot change the theme colour and has to edit the source file.

Output

.btn {
  color: red;
}

@at-root escapes the current nesting scope

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

A .input nested inside .theme-dark compiles to .theme-dark .input (a descendant selector). If the intent was a global style that applies regardless of the theme scope, @at-root is required to lift it back to the top level. This is one of the easiest Sass semantics to get wrong and the hardest to spot by reading.

Output

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

Color functions to derive variants from one theme colour

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

Collapse the brand colour into a single $primary and derive hover, disabled, and tinted backgrounds from it with darken / lighten / mix / rgba, so re-theming touches one line. Note that rgba($color, $alpha) changes alpha, not the colour itself; use rgba($primary, 0.5) for a translucent tint and it composes against the colour as-is.

Output

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

Common Pitfalls

  • Continuing to use @import instead of @use is the most common hazard: @import shares one global scope, so a duplicate $primary or @mixin silently overwrites the earlier one, the build still succeeds, and the shipped colours are simply wrong. Count the @import statements and convert shared variable files to @use "variables" as vars first.
  • Using @import to load a file that contains @use fails to build, and once both module systems are mixed the error points at a completely unrelated file. On "This file is already loaded" or "Can't find stylesheet to import" errors, replace that file's @import with @use.
  • darken / lighten / mix do numeric interpolation, not perceptual lightness adjustment. #6366f1 darkened by 10% does not look uniformly darker, and lighten on yellows is often invisible. When the design demands a clear contrast step, write an explicit hex value or use color.adjust with $lightness.
  • Division: in Sass, 10px / 2 still yields 10px because division only applies in certain contexts, and a ratio needs math.div(10px, 2). In older versions / is a separator, so the mistake compiles cleanly, emits the original value, and the style silently does nothing.
  • @error halts compilation while @warn only prints and continues. Putting @error in a shared mixin's parameter validation means one page passing a bad value fails the entire site build. Reserve it for cases that truly cannot degrade; use @warn everywhere else so the build survives.
  • @extend merges selectors and widens the match, so extending a shared placeholder like %message-box from both .error and .warning can pull in elements you did not intend, and every new @extend forces a full recompile of the stylesheet. Prefer composing styles with a mixin.

Tips

  • SCSS (.scss) is CSS-compatible, while Sass (.sass) uses indentation. SCSS is recommended.
  • @use is Sass's modern module system and is clearer than the legacy @import.
  • Use mixins to reuse code blocks; use % placeholder selectors to reuse styles without emitting duplicate CSS.

FAQ

Both @import and @use load files — which should new projects use?

Use @use. It is the recommended modular system and keeps namespaces explicit. After @use "variables" as vars you reference vars.$primary, while @use "variables" as * drops the prefix and matches the old behaviour. To override a module's defaults (the ones declared with !default), write @use "config" with ($primary: red). The older @import "variables" is legacy syntax with global scope and a real risk of name collisions — keep it out of new code. It still has one legitimate use: pulling in external CSS such as @import url("https://fonts.googleapis.com").

How should I divide work between mixins, @extend and % placeholders?

Mixins reuse a block of declarations and emit properties and values: define @mixin flex-center { display: flex; justify-content: center } and call it with @include flex-center. If callers need to supply their own rules, add @content and pass them in as in .btn { @include button { color: red } }. The % placeholder reuses a shared style group: %message-box { border: 1px solid } is inherited with @extend %message-box and never emits a selector of its own. Rule of thumb — properties go in a mixin, styles shared by a family of selectors go in a placeholder plus @extend.

How do I combine loops with interpolation to generate a family of classes?

The loop controls how many are produced and #{} splices the variable into the selector. @for $i from 1 through 3 { .col-#{$i} { } } yields .col-1 through .col-3; @each $color in red, blue, green { .#{$color} { } } iterates over values; @while $i > 0 { .item-#{$i} { } $i: $i - 1 } runs until the condition fails. Interpolation works in values too: content: "icon-#{$name}" emits a literal icon-xxx string instead of the raw #{$name} characters.

How do I avoid copy-pasting media queries for every breakpoint?

Turn the breakpoint into a parameterised mixin: @mixin responsive($breakpoint) { @media ... } defines the media condition once and callers pass the concrete value. Keep scale values in a map — $sizes: (small: 12px, large: 24px) read with map-get($sizes, small), extended with map-merge($sizes, (medium: 16px)). And when nesting gets too deep, @at-root emits the selector at the top level: .box { @at-root .inner { } } produces .inner rather than .box .inner.

How much do arithmetic and colour functions actually save in SCSS?

Numbers participate directly: width: 100px + 50px compiles to 150px, and helpers like @function px-to-rem($px) { @return $px / 16 * 1rem } package repeated math. On the colour side, darken(#6366f1, 10%), lighten(#6366f1, 10%) and mix(red, blue) derive shades without hand-rolled values, while rgba(#6366f1, 0.5) applies opacity to an existing brand colour. For diagnostics, @warn emits a warning and lets compilation continue, whereas @error aborts the build — handy for validating required mixin arguments.

Official References

Each command links to its official documentation below, so you can verify the latest usage and read deeper.

Maintained by LaoHand

Publicly updated on Jul 21, 2026, continuously proofread against official docs.

Contact Us

Wrong command or description? Send us corrections, business inquiries or product feedback by email.

Contact Us