Sass

Essential Sass/SCSS syntax for variables, nesting, mixins, functions, and more.

languages
sassscsscsspreprocessorfrontendstyling

Variables

// Define variables with $
$primary-color: #3498db;
$font-stack: 'Helvetica Neue', sans-serif;
$base-spacing: 1rem;
$border-radius: 4px;

// Use variables
.button {
  background-color: $primary-color;
  font-family: $font-stack;
  padding: $base-spacing;
  border-radius: $border-radius;
}

// Default values (can be overridden)
$theme-color: blue !default;

// Variable scoping
.container {
  $local-var: 10px;  // only available in this block
  padding: $local-var;
}

Nesting

// Nest selectors to mirror HTML structure
nav {
  background: #333;

  ul {
    list-style: none;
    margin: 0;
  }

  li {
    display: inline-block;
  }

  a {
    color: white;
    text-decoration: none;

    &:hover {    // & references parent selector
      color: #3498db;
    }
  }
}

// Compiles to:
// nav { background: #333; }
// nav ul { list-style: none; margin: 0; }
// nav li { display: inline-block; }
// nav a { color: white; text-decoration: none; }
// nav a:hover { color: #3498db; }

// Parent selector variations
.button {
  &.primary { }      // .button.primary
  &-icon { }         // .button-icon (BEM style)
  .sidebar & { }     // .sidebar .button
}

Partials & Imports

// Partials start with underscore: _variables.scss, _mixins.scss
// They won't compile to separate CSS files

// Import partials (underscore and extension optional)
@use 'variables';
@use 'mixins';

// Access imported members with namespace
.button {
  color: variables.$primary-color;
  @include mixins.flex-center;
}

// Change namespace
@use 'variables' as vars;
@use 'mixins' as *;  // no namespace needed

// Forward for library authors
@forward 'variables';
@forward 'mixins';

// Legacy @import (deprecated but still works)
@import 'variables';
@import 'mixins';

Mixins

// Define a mixin
@mixin flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

// Use a mixin
.container {
  @include flex-center;
}

// Mixin with parameters
@mixin button($bg-color, $text-color: white) {
  background-color: $bg-color;
  color: $text-color;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.btn-primary {
  @include button(#3498db);
}

.btn-danger {
  @include button(#e74c3c, #fff);
}

// Mixin with content block
@mixin media($breakpoint) {
  @if $breakpoint == mobile {
    @media (max-width: 767px) { @content; }
  } @else if $breakpoint == tablet {
    @media (max-width: 1023px) { @content; }
  } @else if $breakpoint == desktop {
    @media (min-width: 1024px) { @content; }
  }
}

.sidebar {
  width: 300px;

  @include media(mobile) {
    width: 100%;
  }
}

Functions

// Define a function
@function calculate-rem($pixels) {
  @return $pixels / 16 * 1rem;
}

// Use the function
.heading {
  font-size: calculate-rem(24);  // 1.5rem
}

// Function with multiple parameters
@function color-shade($color, $percent) {
  @return mix(black, $color, $percent);
}

.dark-blue {
  background: color-shade(#3498db, 20%);
}

// Built-in color functions
$color: #3498db;
lighten($color, 20%);     // lighter shade
darken($color, 20%);      // darker shade
saturate($color, 20%);    // more saturated
desaturate($color, 20%);  // less saturated
adjust-hue($color, 45deg); // shift hue
rgba($color, 0.5);        // add transparency
mix($color1, $color2, 50%); // blend colors
complement($color);       // complementary color

// Built-in number functions
percentage(0.5);          // 50%
round(4.6);               // 5
ceil(4.2);                // 5
floor(4.8);               // 4
abs(-10);                 // 10
min(1, 2, 3);             // 1
max(1, 2, 3);             // 3

// Built-in string functions
quote(hello);             // "hello"
unquote("hello");         // hello
str-length("hello");      // 5
to-upper-case("hello");   // "HELLO"
to-lower-case("HELLO");   // "hello"

// Built-in list functions
$list: 1, 2, 3, 4, 5;
length($list);            // 5
nth($list, 2);            // 2
append($list, 6);         // 1, 2, 3, 4, 5, 6
join($list1, $list2);     // combined list
index($list, 3);          // 3 (position)

Extend & Inheritance

// Base styles to extend
%button-base {
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 1rem;
}

// Extend the placeholder
.btn-primary {
  @extend %button-base;
  background: #3498db;
  color: white;
}

.btn-secondary {
  @extend %button-base;
  background: #95a5a6;
  color: white;
}

// Extend a class (less preferred)
.error {
  border: 1px solid red;
  color: red;
}

.critical-error {
  @extend .error;
  font-weight: bold;
}

Control Directives

// @if / @else if / @else
@mixin theme($mode) {
  @if $mode == dark {
    background: #333;
    color: #fff;
  } @else if $mode == light {
    background: #fff;
    color: #333;
  } @else {
    background: #f5f5f5;
    color: #333;
  }
}

// @for loop
@for $i from 1 through 5 {
  .col-#{$i} {
    width: 20% * $i;
  }
}
// Generates .col-1 { width: 20% } through .col-5 { width: 100% }

// @each loop
$colors: (primary: #3498db, secondary: #2ecc71, danger: #e74c3c);

@each $name, $color in $colors {
  .btn-#{$name} {
    background-color: $color;
  }
}

// Simple list iteration
$sizes: sm, md, lg;

@each $size in $sizes {
  .text-#{$size} {
    font-size: if($size == sm, 0.875rem, if($size == md, 1rem, 1.25rem));
  }
}

// @while loop
$i: 1;
@while $i <= 3 {
  .item-#{$i} {
    width: 100px * $i;
  }
  $i: $i + 1;
}

Maps

// Define a map
$breakpoints: (
  'sm': 576px,
  'md': 768px,
  'lg': 992px,
  'xl': 1200px
);

// Access map values
$tablet: map-get($breakpoints, 'md');  // 768px

// Check if key exists
@if map-has-key($breakpoints, 'md') {
  // key exists
}

// Iterate over map
@each $name, $value in $breakpoints {
  .container-#{$name} {
    max-width: $value;
  }
}

// Map functions
map-keys($breakpoints);     // ('sm', 'md', 'lg', 'xl')
map-values($breakpoints);   // (576px, 768px, 992px, 1200px)
map-merge($map1, $map2);    // combine maps
map-remove($map, 'key');    // remove a key

// Nested maps
$theme: (
  colors: (
    primary: #3498db,
    secondary: #2ecc71
  ),
  spacing: (
    sm: 0.5rem,
    md: 1rem
  )
);

// Access nested values
$primary: map-get(map-get($theme, colors), primary);

Operators

// Arithmetic operators
$width: 100px + 50px;    // 150px
$height: 200px - 50px;   // 150px
$double: 100px * 2;      // 200px
$half: 100px / 2;        // Use math.div() in modern Sass
$remainder: 10 % 3;      // 1

// Modern division (Sass 1.33+)
@use 'sass:math';
$half: math.div(100px, 2);  // 50px

// Comparison operators
$a > $b;    // greater than
$a < $b;    // less than
$a >= $b;   // greater or equal
$a <= $b;   // less or equal
$a == $b;   // equal
$a != $b;   // not equal

// Logical operators
$condition1 and $condition2;  // both true
$condition1 or $condition2;   // either true
not $condition;               // negation

// String concatenation
$family: 'Helvetica' + ', sans-serif';  // "Helvetica, sans-serif"
$class: 'btn-' + primary;               // "btn-primary"

Interpolation

// Use #{} to insert variables into selectors, property names, or strings
$side: left;
$property: margin;

.box {
  #{$property}-#{$side}: 10px;  // margin-left: 10px
}

// In selectors
$component: button;
.#{$component} {
  // .button { ... }
}

// In @media queries
$breakpoint: 768px;
@media (min-width: #{$breakpoint}) {
  // ...
}

// In calc()
$spacing: 20px;
.container {
  width: calc(100% - #{$spacing * 2});
}

// In URLs
$path: '../images';
.hero {
  background: url('#{$path}/hero.jpg');
}

Best Practices

// 1. Organize with partials
// _variables.scss, _mixins.scss, _base.scss, _components.scss
@use 'variables';
@use 'mixins';
@use 'base';
@use 'components';

// 2. Keep nesting shallow (max 3-4 levels)
// ✓ Good
.nav {
  &__item { }
  &__link { }
}

// ✗ Avoid deep nesting
.nav {
  ul {
    li {
      a {
        span { }  // Too deep!
      }
    }
  }
}

// 3. Use variables for repeated values
$spacing-unit: 8px;
$primary-color: #3498db;

// 4. Prefer @use over @import (modern Sass)
@use 'sass:math';
@use 'variables' as vars;

// 5. Use placeholder selectors for @extend
%visually-hidden {
  position: absolute;
  clip: rect(0, 0, 0, 0);
}

.sr-only {
  @extend %visually-hidden;
}