Writing Reusable Logic in SCSS with Functions

SCSS functions streamline stylesheet maintenance by centralising calculations, enabling reusability and easy updates across styles. They compute values efficiently, enhancing code clarity and reducing redundancy in development.

As a stylesheet grows, the same calculations tend to appear in multiple places. A spacing value derived from a base unit, a colour adjusted by a fixed amount, a class name built from a prefix and a component name. Copy-pasting those expressions works until something needs to change, at which point you are hunting through hundreds of lines to update every instance. SCSS functions solve this by letting you write the logic once, give it a name, and call it wherever you need it.

What a Function Does

An SCSS function takes one or more arguments, performs an operation on them, and returns a single computed value. That value can be a number, a colour, a string, or a list. The function itself does not output any CSS properties directly. It just produces a value that you use inside a property declaration, the same way you would use a raw value.

This is the distinction worth understanding early: SCSS also has mixins, which output blocks of CSS rules. Functions are narrower in scope. They compute and return, nothing more.

The Basic Structure

Functions are defined with the @function directive, followed by the function name, its parameters, and a block that must include a @return statement:

@function scale-value($n, $factor) {
@return $n * $factor;
}
.card {
padding: scale-value(8px, 1.5); // Returns 12px
}

The @return line is where the computed result gets handed back to the caller. Without it, the function does nothing useful. Once defined, you call the function the same way you would use any built-in SCSS function, by writing the name followed by arguments in parentheses.

Working with Colours

One of the most practical uses for custom functions is wrapping colour operations so the logic behind your colour system lives in one place rather than being scattered across your stylesheet:

@function adjust-shade($base-color, $amount) {
@return lighten($base-color, $amount);
}
.alert {
background-color: adjust-shade(#e74c3c, 15%); // Lightens by 15%
}
.badge {
background-color: adjust-shade(#2ecc71, 8%);
}

The function wraps the built-in lighten call. This matters when your colour logic becomes more complex later. If you decide the system should darken instead of lighten, or apply a mix of adjustments, you change one function and every caller updates automatically.

Building Strings Dynamically

String interpolation in SCSS lets functions construct values that would otherwise require manual concatenation every time:

@function build-selector($component, $namespace) {
@return "#{$namespace}__#{$component}";
}
.menu {
content: build-selector("item", "nav"); // Returns "nav__item"
}

This is particularly useful in design systems where class names follow a naming convention. Rather than manually typing the convention every time, you encode it in a function and call that instead.

Processing Lists

Functions can iterate over lists to compute aggregate values, which is useful for things like calculating spacing from a set of measurements or averaging values across a scale:

@function list-mean($values) {
$total: 0;
$count: length($values);
@each $val in $values {
$total: $total + $val;
}
@return $total / $count;
}
$spacing-scale: 4, 8, 16, 32;
.section {
margin-bottom: list-mean($spacing-scale); // Returns 15
}

The function loops through the list with @each, accumulates the total, then divides by the count. The result feeds directly into a property value. This approach keeps magic numbers out of your declarations and makes the relationship between the scale and the derived values explicit.

A Few Principles Worth Following

Name functions after what they return, not what they do internally. adjusted-colour or base-spacing tells the caller what to expect. run-lightening-calculation does not.

Keep each function focused on one job. A function that adjusts colours should not also be building class name strings. When a function tries to do two things, it becomes harder to reuse and harder to debug.

Comment parameters on anything non-obvious. If someone reading the code six months from now cannot immediately tell what $amount means in context, a short comment saves them the time of tracing it back through the codebase.

Use @return as early as possible. If a condition is met that determines the output, return there rather than carrying the value through a chain of conditionals to a single return at the bottom. Earlier returns keep the logic path clear.

Why This Matters

The real value of SCSS functions is not any single example, it is the habit they encourage. When you write padding: 16px in three places and later need to change it to 14px, you change three lines. When you write padding: base-spacing(2) in three places and later need to change the base, you change one function. Functions push the decision-making into one place and let the rest of the stylesheet follow automatically.

That is maintainability in practice: not perfect code on the first pass, but code where changes are cheap and contained.

See you soon.

View Comments (7)

Leave a Reply

Subscribe to My Newsletter

Subscribe to my email newsletter to get the latest posts delivered right to your email. Pure inspiration, zero spam.