Skip to content

Sass Custom Functions

This lesson goes deeper into writing your own Sass functions: default parameters, validating input, and using control rules inside a function body to compute more complex values like a full type scale.

Writing a Practical Custom Function

Custom functions shine when a value needs to be computed from other values in a way you'd otherwise repeat throughout a stylesheet, converting units, generating a color scale, or picking a readable contrast color.

@use 'sass:math';

@function to-rem($px, $base: 16px) {
  @return math.div($px, $base) * 1rem;
}

.title {
  font-size: to-rem(32px);       // => 2rem
  margin-bottom: to-rem(24px, 12px); // => 2rem, custom base
}

The $base: 16px default parameter means most calls don't need a second argument, but it's still overridable when needed.

Custom Function Patterns

@function name($param, $default: value) {
  @if condition {
    @return value-a;
  }
  @return value-b;
}
  • Default parameters use the same $name: value syntax as mixins.
  • A function can branch with @if/@else and still guarantee a @return on every path.
  • Functions can call other functions, including recursively.
  • @error can validate arguments and stop compilation with a clear message if input is invalid.

Custom Functions Cheatsheet

Common patterns for writing robust, reusable functions.

Pattern Example Purpose
Default parameter @function rem($px, $base: 16px) Optional argument with a sensible fallback
Conditional return @if $dark { @return black; } Branch logic before returning
Input validation @if not $valid { @error ...; } Fail fast on bad input
Recursive call @return sum($list, $i + 1); Function calling itself
Return a map @return (width: $w, height: $h); Return multiple related values as one map

Validating Function Input

A well-written custom function checks its arguments and fails loudly with @error rather than silently producing incorrect CSS, which is especially important for functions shared across a team or published as a library.

@use 'sass:meta';

@function to-rem($px) {
  @if meta.type-of($px) != 'number' {
    @error "to-rem() expects a number, got #{meta.type-of($px)}.";
  }

  @return math.div($px, 16px) * 1rem;
}

Computing a Readable Contrast Color

A genuinely useful real-world function: given a background color, decide whether black or white text is more readable, based on the color's lightness.

@use 'sass:color';

@function contrast-color($bg, $light: white, $dark: #1f2937) {
  @return if(color.lightness($bg) > 55%, $dark, $light);
}

.badge {
  background: #f59e0b;
  color: contrast-color(#f59e0b);
}

Recursive Functions

Because Sass functions can call themselves, you can implement recursive algorithms, useful for tasks like summing a list of values or generating a sequence of related sizes.

@function sum($list, $i: 1, $total: 0) {
  @if $i > length($list) {
    @return $total;
  }
  @return sum($list, $i + 1, $total + nth($list, $i));
}

$widths: 20px, 30px, 50px;
$total-width: sum($widths); // => 100px

Common Mistakes

  • Not validating function arguments, leading to confusing downstream CSS errors instead of a clear message at the source.
  • Writing a recursive function without a proper base case, causing infinite recursion and a compiler error.
  • Overcomplicating a function that could be a simple variable or a built-in function call instead.
  • Returning inconsistent types from different branches of the same function (sometimes a number, sometimes a string), which makes the function unpredictable to use.

Key Takeaways

  • Custom functions can use default parameters, conditional logic, and even recursion.
  • Validate function input with @error to fail fast with a clear message instead of producing silently broken CSS.
  • A function like contrast-color() can encode real design logic, not just simple math.
  • Keep a function's return type consistent across every possible branch.

Pro Tip

Write a short comment above any non-trivial custom function explaining its parameters and return value, exactly like a JSDoc comment, future contributors (including future you) will thank you when reusing it months later.