Click ★ if you like the project. Your contributions are heartily ♡ welcome.
- Sass Overview
- Sass Variables
- Sass Nesting
- Sass Partials
- Sass @mixin
- Sass @extend
- Sass Directives
- Sass Functions
- Sass String
- Sass Numeric
- Sass List
- Sass Map
- Sass Selector
- Sass Color
- Sass Miscellaneous
The Sass ( which stands for 'Syntactically awesome style sheets ) is an extension of CSS that enables you to use things like variables, nested rules, modules (@use/@forward), mixins, and more. It also helps to keep things organized and allows you to create style sheets faster.
Sass works by writing your styles in .scss (or .sass) files, which will then get compiled into a regular CSS file. The newly compiled CSS file is what gets loaded to your browser to style your web application. This allows the browser to properly apply the styles to your web page.
⚝ Try this example on CodeSandbox
File splitting helps organize your CSS into multiple files, decreasing page load time and making things easier to manage. How you decide to split them up is up to you, but it can be useful to separate files by component. For example, we can have all button styles in a file called _buttons.scss or all your header-specific styles in a file called _header.scss, main file, say _app.scss, and we can import those files by writing @use 'buttons';
Variables are useful for things like colors, fonts, font sizes, and certain dimensions, as you can be sure always using the same ones. Variables in SCSS start with $ sign
SCSS Style:
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}CSS Style:
body {
font: 100% Helvetica, sans-serif;
color: #333;
}When the Sass is processed, it takes the variables we define for the $font-stack and $primary-color and outputs normal CSS with our variable values placed in the CSS. This can be extremely powerful when working with brand colors and keeping them consistent throughout the site.
⚝ Try this example on CodeSandbox
Interpolation allows us to interpolate sass expressions into a simple Sass or CSS code. Means, you can define selector name, property name, CSS at-rules, quoted or unquoted strings etc, as a variable.
Syntax:
#{$variable_name}SCSS Style:
@mixin corner-icon($name) {
/* using interpolation */
.icon-#{$name} {
background-image: url("/icons/#{$name}.svg");
}
}
/* calling the above mixin */
@include corner-icon("mail");CSS Style:
.icon-mail {
background-image: url("/icons/mail.svg");
}Here, the value of the $name variable is added wherever we used #{$name} in our stylesheet.
The !default flag assigns a value to a variable only if that variable is not already defined or is null. It is useful in libraries/partials to set a fallback value that consumers can override before importing.
SCSS Style:
// _library.scss
$border-radius: 4px !default;
$primary-color: #3498db !default;
.button {
border-radius: $border-radius;
background-color: $primary-color;
}// main.scss — override BEFORE @use
$primary-color: #e74c3c; // overrides the !default
@use 'library';CSS Style:
.button {
border-radius: 4px; /* !default kept as-is */
background-color: #e74c3c; /* overridden by consumer */
}Sass variables follow lexical scope rules. A variable declared inside a rule/mixin is local to that block. The !global flag promotes a local variable to the module (global) scope.
SCSS Style:
$color: blue; // global
.card {
$color: red; // local — does not affect the global $color
background: $color; // red
}
p {
color: $color; // blue (global is unchanged)
}Using !global to update a global variable from inside a block:
$theme: light;
@mixin dark-mode {
$theme: dark !global; // modifies the global $theme
body { background: black; }
}
@include dark-mode;
// $theme is now "dark" hereBasic nesting refers to the ability to have a declaration inside of a declaration.
SCSS Style:
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}CSS Style:
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav li {
display: inline-block;
}
nav a {
display: block;
padding: 6px 12px;
text-decoration: none;
}⚝ Try this example on CodeSandbox
Sass allows media queries to be nested inside selectors, keeping responsive styles co-located with the component they target. The compiled CSS hoists them to the top level automatically.
SCSS Style:
.sidebar {
width: 300px;
background: #f4f4f4;
@media (max-width: 768px) {
width: 100%;
background: #fff;
}
}CSS Style:
.sidebar {
width: 300px;
background: #f4f4f4;
}
@media (max-width: 768px) {
.sidebar {
width: 100%;
background: #fff;
}
}The & character refers to the parent selector at any point inside a rule. It is essential for writing pseudo-classes, pseudo-elements, BEM modifiers, and state-based styles without breaking nesting.
SCSS Style:
.button {
background: #3498db;
color: white;
&:hover { background: darken(#3498db, 10%); }
&:active { transform: scale(0.98); }
// BEM modifier
&--primary { background: #2ecc71; }
&--danger { background: #e74c3c; }
// state class on same element
&.is-disabled {
opacity: 0.5;
pointer-events: none;
}
}CSS Style:
.button { background: #3498db; color: white; }
.button:hover { background: #217dbb; }
.button:active { transform: scale(0.98); }
.button--primary { background: #2ecc71; }
.button--danger { background: #e74c3c; }
.button.is-disabled { opacity: 0.5; pointer-events: none; }By default, Sass transpiles all the .scss files directly. However, when you want to import a file, you do not need the file to be transpiled directly. If you start the filename with an underscore, Sass will not transpile it. Files named this way are called partials in Sass.
Example:
The following example shows a partial Sass file named "_colors.scss".
/**
* "_colors.scss
*/
$myPink: #EE82EE;
$myBlue: #4169E1;
$myGreen: #8FBC8F;Now, if you use the partial file, omit the underscore. Sass understands that it should load the file "_colors.scss". Variables are accessed via the namespace:
/**
* Sass Partials
*/
@use "colors";
body {
font-family: Helvetica, sans-serif;
font-size: 18px;
color: colors.$myBlue;
}@import is the legacy loading rule (deprecated and removed in Dart Sass 3.0). @use is the modern replacement that provides namespacing, visibility control, and avoids duplicate CSS output.
| Feature | @import |
@use |
|---|---|---|
| Namespace | None — globals leak | Automatic (filename) |
| Loaded multiple times? | Yes — duplicate CSS | No — loaded once |
Private members (_) |
Not enforced | Enforced |
| Configuring defaults | Not supported | with ($var: value) |
SCSS Style:
// _colors.scss
$primary: #3498db;
$danger: #e74c3c;
// main.scss — @use (modern)
@use 'colors';
@use 'colors' as c; // custom namespace
@use 'colors' as *; // no namespace (use sparingly)
.hero { color: colors.$primary; }
.alert { background: c.$danger; }Configuring a module via with:
@use 'library' with (
$border-radius: 8px,
$primary-color: #2ecc71
);@forward re-exports members (variables, mixins, functions) from one file through another so consumers only need a single @use. It is the building block of Sass index files (_index.scss).
Example:
// _colors.scss
$primary: #3498db;
// _typography.scss
$base-size: 16px;
// _index.scss — forward both partials
@forward 'colors';
@forward 'typography';
// main.scss — one import to get everything
@use 'index' as theme;
body {
color: theme.$primary;
font-size: theme.$base-size;
}You can also control visibility with show / hide:
@forward 'colors' show $primary, $danger;
@forward 'utils' hide $internal-helper;A mixin lets you make groups of CSS declarations that you want to reuse throughout your site.
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
@mixin button($bg-color, $text-color: white) {
background-color: $bg-color;
color: $text-color;
padding: 0.5em 1em;
border: none;
border-radius: 4px;
cursor: pointer;
}.card { @include flex-center; }
.primary-btn { @include button(#3498db); }
.danger-btn { @include button(#e74c3c, #fff); }DRY-ing out a mixin means splitting it into static and dynamic parts. The dynamic mixin is the one the user is going to call, and the static mixin is only going to contain the pieces that would otherwise get duplicated.
Example:
@mixin button($color) {
@include button-static;
background-color: $color;
border-color: mix(black, $color, 25%);
&:hover {
background-color: mix(black, $color, 15%);
border-color: mix(black, $color, 40%);
}
}
@mixin button-static {
border: 1px solid;
border-radius: 5px;
padding: .25em .5em;
&:hover {
cursor: pointer;
}
}Arguments can have default values so callers can omit them. Defaults are evaluated at call time and can reference earlier parameters.
SCSS Style:
@mixin border-radius($radius: 4px, $color: transparent) {
border-radius: $radius;
border: 1px solid $color;
}
.card { @include border-radius; } // uses defaults
.pill { @include border-radius(50px); } // custom radius
.outlined { @include border-radius(4px, #ccc); } // all customCSS Style:
.card { border-radius: 4px; border: 1px solid transparent; }
.pill { border-radius: 50px; border: 1px solid transparent; }
.outlined { border-radius: 4px; border: 1px solid #ccc; }Adding ... after the last parameter name makes it accept any number of arguments, collected into a list. You can also splat a list or map back out with ....
SCSS Style:
@mixin shadows($shadows...) {
box-shadow: $shadows;
}
.card {
@include shadows(0 2px 4px rgba(0,0,0,.1), 0 8px 16px rgba(0,0,0,.2));
}CSS Style:
.card {
box-shadow: 0 2px 4px rgba(0,0,0,.1), 0 8px 16px rgba(0,0,0,.2);
}Splatting a list into a mixin call:
$my-shadows: 0 1px 3px #999, 0 4px 8px #888;
.panel { @include shadows($my-shadows...); }@extend directive provides a simple way to allow a selector to inherit/extend the styles of another one.
.message {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
@extend .message;
border-color: green;
}
.error {
@extend .message;
border-color: red;
}Using @extend lets you share a set of CSS properties from one selector to another.
SCSS Style:
/* This CSS will print because %message-shared is extended. */
%message-shared {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
// This CSS won\'t print because %equal-heights is never extended.
%equal-heights {
display: flex;
flex-wrap: wrap;
}
.message {
@extend %message-shared;
}
.success {
@extend %message-shared;
border-color: green;
}
.error {
@extend %message-shared;
border-color: red;
}
.warning {
@extend %message-shared;
border-color: yellow;
}CSS Style:
/* This CSS will print because %message-shared is extended. */
.message, .success, .error, .warning {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
border-color: green;
}
.error {
border-color: red;
}
.warning {
border-color: yellow;
}⚝ Try this example on CodeSandbox
@mixin / @include |
@extend |
|
|---|---|---|
| Arguments | Yes | No |
| Output | Duplicates CSS per include | Groups selectors (no duplication) |
| Use case | Dynamic / parameterised styles | Sharing identical static styles |
| Works across files | Yes | Same file or module only |
@mixin — each @include outputs a full copy of the rules:
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
.hero { @include flex-center; }
.modal { @include flex-center; }@extend — selectors are grouped, CSS is output once:
%flex-center {
display: flex;
justify-content: center;
align-items: center;
}
.hero { @extend %flex-center; }
.modal { @extend %flex-center; }CSS output from @extend:
.hero, .modal {
display: flex;
justify-content: center;
align-items: center;
}Use @mixin when you need arguments or dynamic values; prefer @extend (with %placeholders) for static, shared styles.
The Sass @if directive and its companions @else if and @else, allow you to include Sass code in the CSS output only if certain conditions are met.
Example 01: if Condition
$test: 10;
p {
@if $test < 5 {
color: blue;
}
}Example 02: Nested if Conditions
$test: 10;
p {
@if $test < 10 {
color: blue;
@if $test == 5 {
text-color: white;
}
}
}The @while directive will continue to output CSS produced by the statements while the condition returns true.
SCSS Style:
$p: 3;
@while $p < 5 {
.item-#{$p} {
color: red;
$p : $p + 1;
}
}CSS Style:
.item-3 {
color: red;
}
.item-4 {
color: red;
}The @for directive to execute a group of statement a specific number of times. It has two variations. The first, which uses the through keyword, executes the statements from <start> to <end>, inclusive:
SCSS Style:
@for $i from 1 through 3 {
.list-#{$i} {
width: 2px * $i;
}
}CSS Style:
.list-1 {
width: 2px;
}
.list-2 {
width: 4px;
}
.list-3 {
width: 6px;
}The @at-root directive is a collection of nested rules which is able to make the style block at root of the document. @at-root selector excludes the selector by default. By using @at-root, we can move the style outside of nested directive.
Syntax:
@at-root (without: ...) and @at-root (with: ...)SCSS Style:
@media print {
.style {
height: 8px;
@at-root (without: media) {
color: #808000;;
}
}
}CSS Style:
The above code will be compiled to the CSS file as shown below −
@media print {
.style {
height: 8px;
}
}
.style {
color: #808000;
}1. The @error Directive:
It prints the value of the expression along with a stack trace indicating how the current mixin or function was called. Once the error is printed, Sass stops compiling the stylesheet and tells whatever system is running it that an error occurred.
@use 'sass:map';
@function color-variation($color) {
@if map.has-key($colors, $color) {
@return map.get($colors, $color);
}
@error "Invalid color name: `#{$color}`.";
}Output:
>> Invalid color name: `brand-orange`.
>> Line 9 Column 7 sass/common.scss2. The @debug Directive:
It prints the value of that expression, along with the filename and line number.
$color-green: #00FF00;
$font-sizes: 10px + 20px;
.container {
@debug $color-green;
@debug $font-sizes;
}Output:
>> common.scss:10: DEBUG: #00FF00
>> common.scss:11: DEBUG: 30pxThe @content directive allows us to pass a content block into a mixin.
SCSS Style:
/**
* @content directive
*/
@mixin media($width) {
@media only screen and (max-width: $width) {
@content;
}
}
@include media(320px) {
background: red;
}CSS Style:
@media only screen and (max-width: 320px) {
background: red;
}The @each directive iterates over every item in a list or map and generates styles for each.
SCSS Style (list):
$sizes: 8px, 16px, 24px, 32px;
@each $size in $sizes {
.m-#{$size} { margin: $size; }
}CSS Style:
.m-8px { margin: 8px; }
.m-16px { margin: 16px; }
.m-24px { margin: 24px; }
.m-32px { margin: 32px; }SCSS Style (map):
$theme-colors: (
"primary": #3498db,
"success": #2ecc71,
"danger": #e74c3c,
"warning": #f39c12
);
@each $name, $color in $theme-colors {
.btn-#{$name} {
background-color: $color;
color: white;
}
}CSS Style:
.btn-primary { background-color: #3498db; color: white; }
.btn-success { background-color: #2ecc71; color: white; }
.btn-danger { background-color: #e74c3c; color: white; }
.btn-warning { background-color: #f39c12; color: white; }@warn prints a warning message to standard error without stopping compilation. It is used in libraries to alert consumers about deprecated usage or incorrect arguments, while still producing CSS.
@mixin deprecated-flex($value) {
@if $value == "box" {
@warn "The 'box' flexbox syntax is deprecated. Use 'flex' instead.";
}
display: $value;
}
.container { @include deprecated-flex("box"); }Output (stderr):
Warning: The 'box' flexbox syntax is deprecated. Use 'flex' instead.
on line 3 of style.scss
%placeholder: are classes that aren't output when your SCSS is compiled
%awesome {
width: 100%;
height: 100%;
}
body {
@extend %awesome;
}
p {
@extend %awesome;
}/* Output */
body, p {
width: 100%;
height: 100%;
}Custom functions are created with @function and must return a value with @return. Unlike mixins, they compute and return a single value — not a set of CSS declarations.
SCSS Style:
@use 'sass:math';
// Convert px to rem
@function to-rem($px, $base: 16) {
@return math.div($px, $base) * 1rem;
}
// Calculate fluid spacing
@function fluid($min, $max, $min-vw: 320, $max-vw: 1200) {
$slope: math.div($max - $min, $max-vw - $min-vw);
$y-intercept: $min - $slope * $min-vw;
@return clamp(#{$min}px, #{$y-intercept}px + #{$slope * 100}vw, #{$max}px);
}
h1 { font-size: to-rem(32px); } // 2rem
h2 { font-size: to-rem(24px); } // 1.5rem
.section { padding: fluid(16, 48); } // clamp(16px, …, 48px)CSS Style:
h1 { font-size: 2rem; }
h2 { font-size: 1.5rem; }
.section { padding: clamp(16px, -8px + 3.25vw, 48px); }$default-font: 'Lucida';
p {
font-family: $default-font, "Ariel", sans-serif;
}All string functions live in the sass:string module. Load it with @use 'sass:string'.
| Function | Description | Example |
|---|---|---|
string.quote($str) |
Adds quotes | string.quote(hello) → "hello" |
string.unquote($str) |
Removes quotes | string.unquote("hello") → hello |
string.length($str) |
Character count | string.length("hello") → 5 |
string.to-upper-case($str) |
Uppercase | string.to-upper-case("hi") → "HI" |
string.to-lower-case($str) |
Lowercase | string.to-lower-case("Hi") → "hi" |
string.slice($str, $start, $end) |
Substring | string.slice("hello", 2, 4) → "ell" |
string.index($str, $substr) |
Find position | string.index("hello", "ll") → 3 |
string.insert($str, $insert, $index) |
Insert at index | string.insert("hello", " world", 6) → "hello world" |
SCSS Style:
@use 'sass:string';
$name: "button";
.component {
content: string.to-upper-case($name); // "BUTTON"
font-family: string.unquote("Helvetica, sans-serif");
}p {
font-size: 3em * 1.5;
}Sass allows for mathematical operations such as addition, subtraction, multiplication and division. They automatically convert between compatible units.
In Dart Sass, / is no longer a division operator — use math.div() from sass:math instead.
SCSS Style:
/**
* style.scss
*/
@use 'sass:math';
$size: 25px;
h2 {
font-size: $size + 5; // 30px
}
h3 {
font-size: math.div($size, 5); // 5px
}
.para1 {
font-size: $size * 1.5; // 37.5px
}
.para2 {
font-size: $size - 10; // 15px
}CSS Style:
h2 {
font-size: 30px;
}
h3 {
font-size: 5px;
}
.para1 {
font-size: 37.5px;
}
.para2 {
font-size: 15px;
}// Separated by commas.
$number-list: 10, 23, 10;
// Separated by spaces.
$number-list2: 10px 20px 30px;
// Nested list.
$number-list3: 10, 20 30, 10;
// Nested list same as $number-list3.
$number-list4: 10, (20 30), 10; All list functions live in the sass:list module. Load it with @use 'sass:list'.
| Function | Description | Example |
|---|---|---|
list.length($list) |
Number of items | list.length(1 2 3) → 3 |
list.nth($list, $n) |
Item at index (1-based) | list.nth(a b c, 2) → b |
list.index($list, $value) |
Position of value | list.index(a b c, b) → 2 |
list.append($list, $val) |
Append a value | list.append(1 2, 3) → 1 2 3 |
list.join($l1, $l2) |
Concatenate two lists | list.join(1 2, 3 4) → 1 2 3 4 |
list.zip($lists...) |
Interleave lists | list.zip(a b, 1 2) → (a 1)(b 2) |
list.set-nth($list, $n, $val) |
Replace item at index | list.set-nth(a b c, 2, x) → a x c |
SCSS Style:
@use 'sass:list';
$colors: red, green, blue;
// iterate with @each
@each $color in $colors {
.text-#{$color} { color: $color; }
}
// check length
@debug list.length($colors); // 3
// get specific item
@debug list.nth($colors, 2); // green
// append to list
$extended: list.append($colors, purple);
@debug $extended; // red, green, blue, purpleAll map functions are now in the sass:map module. Load it with @use 'sass:map' and call functions via the map. namespace.
Available functions:
- map.get($map, $key)
- map.merge($map1, $map2)
- map.keys($map)
- map.has-key($map, $key)
- map.remove($map, $keys...)
- map.values($map)
- map.set($map, $key, $value) (new in Dart Sass)
@use 'sass:map';Example 01: map.get($map, $key)
$font-sizes: ("small": 12px, "normal": 18px, "large": 24px);
map.get($font-sizes, "small") // 12pxExample 02: map.has-key($map, $key)
$font-sizes: ("small": 12px, "normal": 18px, "large": 24px);
map.has-key($font-sizes, "big") // falseExample 03: map.keys($map)
$font-sizes: ("small": 12px, "normal": 18px, "large": 24px);
map.keys($font-sizes) // "small", "normal", "large"Example 04: map.merge($map1, $map2)
$font-sizes: ("small": 12px, "normal": 18px, "large": 24px);
$font-sizes2: ("x-large": 30px, "xx-large": 36px);
map.merge($font-sizes, $font-sizes2)
// "small": 12px, "normal": 18px, "large": 24px, "x-large": 30px, "xx-large": 36pxExample 05: map.remove($map, $keys...)
$font-sizes: ("small": 12px, "normal": 18px, "large": 24px);
map.remove($font-sizes, "small") // ("normal": 18px, "large": 24px)Example 06: map.values($map)
$font-sizes: ("small": 12px, "normal": 18px, "large": 24px);
map.values($font-sizes) // 12px, 18px, 24pxExample 07: map.set($map, $key, $value) (Dart Sass only)
$font-sizes: ("small": 12px, "normal": 18px, "large": 24px);
map.set($font-sizes, "xlarge", 32px)
// ("small": 12px, "normal": 18px, "large": 24px, "xlarge": 32px)Sass provides the data type called map which represents one or more pairs of key values. The map, which returns a map, provides a new map and does not modify the initial map.
Example:
/**
* map.get()
*/
$font-weights: ("regular": 400, "medium": 500, "bold": 700);
@debug map.get($font-weights, "medium"); // 500
@debug map.get($font-weights, "extra-bold"); // nullPlaceholder is special kind of selector which is used for writing own Sass library. Its work is very similar to mixin without arguments. Placeholder selector starts with a % sign. Placeholder selectors are excluded in the compilation of the Sass file
Syntax:
@extend %( name_of_selector );SCSS Style:
%button-format {
padding: 10px 20px;
border-radius: 15px;
color: black;
}
.toolbar-button {
@extend %button-format;
background-color: lightpink;
&:hover {
background-color: rgb(155, 106, 114);
}
}
.status-bar-button {
@extend %button-format;
background-color: lightblue;
&:hover {
background-color: blue;
}
}CSS Style:
.status-bar-button, .toolbar-button {
padding: 10px 20px;
border-radius: 15px;
color: black;
}
.toolbar-button {
background-color: lightpink;
}
.toolbar-button:hover {
background-color: #9b6a72;
}
.status-bar-button {
background-color: lightblue;
}
.status-bar-button:hover {
background-color: blue;
}A combinator is something that explains the relationship between the selectors. A CSS selector can contain more than one simple selector. Between the simple selectors, we can include a combinator.
There are four different combinators in CSS:
- Descendant selector (space)
- Child selector (>)
- Adjacent sibling selector (+)
- General sibling selector (~)
Example 01: Without the combined child selector
card {
outer {
inner {
color: red;
}
}
}Example 02: Using > selector
card {
> outer {
> inner {
color: red;
}
}
}The sass avoids the rewrite code using the nesting method. To refer the parent selector and inside of parent selector & symbol is required. This symbol used for hover, focus and active status in style tag.
.alert {
// The parent selector can be used to add pseudo-classes to the outer
// selector.
&:hover {
font-weight: bold;
}Dart Sass supports all CSS color syntaxes, including modern wide-gamut color spaces.
// Legacy color syntaxes:
$primary: rgb(214, 121, 45);
$semi: rgba(210, 122, 54, 0.5);
$hsl: hsl(0, 0%, 100%);
$hsla: hsla(100, 60%, 60%, 0.7);
// Modern color spaces (CSS Color Level 4):
$oklch: oklch(60% 0.15 210); // perceptually uniform
$oklab: oklab(60% -0.1 0.05);
$p3: color(display-p3 0.8 0.3 0.1);
$hdr: color(rec2020 0.5 0.2 0.8);For programmatic color manipulation use sass:color module functions:
@use 'sass:color';
$base: #3498db;
.lighter { color: color.adjust($base, $lightness: 15%); }
.darker { color: color.adjust($base, $lightness: -15%); }
.mixed { color: color.mix($base, black, $weight: 80%); }
.scaled { color: color.scale($base, $saturation: -30%); }All color functions live in the sass:color module (@use 'sass:color'). Dart Sass distinguishes between adjust, scale, and change:
| Function | Behaviour | Example |
|---|---|---|
color.adjust($color, $channel: val) |
Adds/subtracts a fixed amount | color.adjust(#036, $lightness: 20%) |
color.scale($color, $channel: %) |
Scales proportionally (%) | color.scale(#036, $saturation: -50%) |
color.change($color, $channel: val) |
Sets an absolute value | color.change(#036, $red: 255) |
color.mix($c1, $c2, $weight: 50%) |
Blends two colors | color.mix(red, blue, 25%) |
color.complement($color) |
Returns the hue complement | color.complement(#036) |
color.invert($color, $weight: 100%) |
Inverts the color | color.invert(#036) |
color.grayscale($color) |
Converts to grayscale | color.grayscale(#036) |
color.alpha($color) |
Returns the alpha channel | color.alpha(rgba(0,0,0,0.5)) → 0.5 |
SCSS Style:
@use 'sass:color';
$brand: #3498db;
// Tint / shade helpers
@function tint($color, $weight) { @return color.mix(white, $color, $weight); }
@function shade($color, $weight) { @return color.mix(black, $color, $weight); }
.btn-light { background: tint($brand, 80%); }
.btn-dark { background: shade($brand, 30%); }
.btn-desatd { background: color.scale($brand, $saturation: -60%); }Dart Sass supports two output styles: expanded (default) and compressed. The legacy :nested and :compact styles were removed in Dart Sass 2.0.
expanded (default)
Each rule and declaration is on its own line. This is the human-readable default output.
sass style.scss style.css --style expandedmain {
padding: 12px 24px;
margin-bottom: 24px;
}
article {
background-color: #00ff00;
color: red;
border: 1px solid blue;
}
article p {
font-size: 18px;
font-style: italic;
margin-bottom: 12px;
}compressed
Removes all whitespace and comments (except /*! preserved comments) to produce the smallest possible file, ideal for production builds.
sass style.scss style.css --style compressedmain{padding:12px 24px;margin-bottom:24px}article{background-color:#00ff00;color:red;border:1px solid blue}article p{font-size:18px;font-style:italic;margin-bottom:12px}Sass supports two syntaxes for the same language. Both compile to identical CSS.
.sass (Indented) |
.scss (Sassy CSS) |
|
|---|---|---|
Braces {} |
Not used — indentation defines blocks | Required |
Semicolons ; |
Not used | Required |
| File extension | .sass |
.scss |
| Compatibility | Sass-only | Superset of CSS — any valid CSS is valid SCSS |
| Adoption | Less common | Industry standard |
Sass (indented) syntax:
$primary: #3498db
nav
background: $primary
ul
list-style: none
a
color: whiteSCSS syntax:
$primary: #3498db;
nav {
background: $primary;
ul { list-style: none; }
a { color: white; }
}Recommendation: Use .scss — it is a superset of CSS so existing CSS files can be renamed to .scss immediately, and it is universally supported by tooling.
A source map is a JSON file (.css.map) that maps each line of compiled CSS back to the original .scss source file and line number. Browser DevTools use it to show you SCSS source instead of minified CSS when debugging.
Generate a source map:
sass style.scss style.css --source-mapDisable source maps (production):
sass style.scss style.css --no-source-map --style compressedSource maps are enabled by default when compiling in development mode. They are embedded or written as a separate .map file depending on the --embed-source-map flag.
| Feature | CSS | Sass/SCSS |
|---|---|---|
| Variables | Custom properties (--var) only |
$variables + custom properties |
| Nesting | Not supported (native nesting in CSS Level 5) | Full nesting since day one |
| Mixins | No | @mixin / @include |
| Functions | Limited built-in | Custom @function + rich built-ins |
| Loops | No | @for, @each, @while |
| Conditionals | No | @if / @else |
| Partials / Modules | @import only |
@use and @forward |
| Math | calc() only |
Native arithmetic + sass:math |
| Compilation | Runs in browser | Compiled to CSS before deployment |
Sass/SCSS is a preprocessor — it adds programming constructs that make large style sheets more maintainable, and compiles down to plain CSS for the browser.
