Sass/SCSS Cheat Sheet
Covers Sass/SCSS variables, nesting, mixins, functions, and the modern @use/@forward module system for writing maintainable CSS.
Variables & Nesting
Declaring variables and nesting selectors.
// Variables$primary-color: #3498db;$spacing: 16px;// Nesting.card { padding: $spacing; border: 1px solid $primary-color; &:hover { // parent selector reference box-shadow: 0 2px 8px rgba(0, 0, 0, .15); } .title { // nested descendant selector font-weight: bold; }}
Mixins & Functions
Reusable style blocks and custom value calculations.
@mixin flex-center($gap: 0) { display: flex; align-items: center; justify-content: center; gap: $gap;}.btn-row { @include flex-center(8px);}@function rem($px, $base: 16) { @return ($px / $base) * 1rem;}.title { font-size: rem(24); // 1.5rem}
Partials & Modules
Splitting styles across files with @use and @forward.
// _colors.scss (partial, filename starts with _)$primary: #3498db;$danger: #e74c3c;// main.scss@use 'colors'; // modern module system@use 'colors' as c; // with alias.alert { background: colors.$primary; // namespaced access}// Legacy (older Sass, still common in existing codebases):@import 'colors'; // deprecated, being phased out
Control Directives
Logic constructs for generating CSS programmatically.
- @if / @else if / @else- conditionally generate CSS rules based on a Sass expression
- @each $item in $list- loop over a list or map, binding each value to a variable
- @for $i from 1 through 5- numeric loop, inclusive of the end value (use to instead of through to exclude it)
- @while $i < 5- loop while a condition remains true
- %placeholder + @extend- share a block of styles across selectors without duplicating declarations
- Nested @media- write media queries inside a selector's own nesting block instead of duplicating the selector
Sass Maps
Key/value data structures for building design-token lookups and generating utility classes.
$breakpoints: ( 'sm': 640px, 'md': 768px, 'lg': 1024px,);@mixin respond($key) { @if not map.has-key($breakpoints, $key) { @error "Unknown breakpoint: #{$key}"; } @media (min-width: map.get($breakpoints, $key)) { @content; }}.container { width: 100%; @include respond('md') { width: 720px; }}// iterate a map to generate classes@each $name, $width in $breakpoints { .hide-#{$name} { @media (min-width: $width) { display: none; } }}
Mixins with @content and Multiple Blocks
Passing a style block into a mixin, including named content blocks (Dart Sass 1.41+).
@mixin theme-variants { .light & { @content(light); } .dark & { @content(dark); }}.card { @include theme-variants using ($mode) { @if $mode == dark { background: #1a1a1a; color: #eee; } @else { background: #fff; color: #111; } }}// classic single @content mixin, still the common case@mixin hover-focus { &:hover, &:focus-visible { @content; }}.link { @include hover-focus { text-decoration: underline; }}
Built-in Sass Modules
The math, color, list, and string modules that replaced legacy global functions in the modern @use system.
@use 'sass:math';@use 'sass:color';@use 'sass:list';@use 'sass:string';.el { width: math.div(960px, 12); // 80px -- replaces the deprecated `/` division margin: math.clamp(8px, 2vw, 24px); background: color.adjust(#3498db, $lightness: -10%); border-color: color.mix(#3498db, #e74c3c, 30%);}$sizes: sm, md, lg;$first: list.nth($sizes, 1); // sm$joined: string.insert('helloworld', ' ', 6); // 'hello world'
Architecture & Tooling Patterns
Conventions for structuring larger Sass codebases beyond a single stylesheet.
- 7-1 pattern- seven folders (abstracts, base, components, layout, pages, themes, vendors) forwarded from one main.scss entry point
- @forward with prefix/show/hide- @forward 'buttons' as btn-* re-exports members under a namespace, or exposes only a subset
- !default flag- $color: blue !default; lets a partial's default be overridden by whoever @uses it, enabling themeable libraries
- !global flag- assigns to a variable in the global scope from inside a block (e.g. inside @each), needed since Sass scoping is block-local by default
- Placeholder selectors (%name)- @extend %name shares declarations without emitting the placeholder itself, avoiding the bloat of extending a real class
- @use ... with (...)- configure a module's !default variables at import time: @use 'buttons' with ($radius: 8px)
- meta.load-css()- dynamically load a module's CSS with a computed path/namespace, useful for theme-switching entry points
Custom Functions & Error Handling
Writing validated utility functions that fail loudly on bad input instead of emitting broken CSS.
@use 'sass:meta';@function px-to-rem($px, $base: 16px) { @if meta.type-of($px) != 'number' { @error "px-to-rem() expects a number, got #{meta.type-of($px)}."; } @if math.unit($px) != 'px' { @warn "Expected px unit, got #{math.unit($px)} -- treating as unitless."; } @return math.div($px, $base) * 1rem;}.title { font-size: px-to-rem(24px); // 1.5rem}// debug output during compilation@debug "compiling title styles, base font: #{$base}";
Use @use instead of @import for new code (import is deprecated and being removed from the language), and keep shared variables in a single partial forwarded via @forward so consumers only need one entry-point import.