HTML & CSS
Article

Sass Basics: The Function Directive

By Reggie Dawson

I recently wrote an article about the basics of Sass, specifically the @mixin directive. In keeping with the theme of highlighting the basics of Sass, this time I will be talking about the @function directive.

What a function does

@function remy($pxsize) {
    @return ($pxsize/16)+rem;
}

h1 { font-size: remy(32);}

A function looks a lot like a mixin, and they both accept the same types of arguments. Although they look similar,a Sass function behaves differently. While a mixin makes our life easier by lessening typing repetitive code, a function allows you to strip repeatable logic from your code. For example, in the code above we are using a function to calculate a rem value for a given pixel size. The resulting code would be:

h1 { font-size: 2rem; }

As you can see instead of applying styles to an element like you would with a mixin, all a function does is return a value for use in your stylesheets.

Function or a Mixin

The key to understanding when to use a function versus a mixin is knowing what you want. A mixin is used to create styles that would be a chore to continually write. Using a mixin you could easily write these styles with one line of code. When writing mixins you will be tempted to include calculations. We could have wrote the remy function as a mixin:

@mixin remy ($pxsize) {
    font-size: ($pxsize/16)+rem;
}

h1 { @include remy(32);}

This would work but it is counter productive. First of all the mixin is locked into just calculating rem for font-size. What if we wanted to use our mixin for other properties? We could rewrite the mixin to take different arguments but that would be overkill.

A function on the other hand is designed to return a value. When you need to generate styles, use a mixin. When you need to encapsulate some logic, especially if you intend to use it across different elements in your project, then use a function. We can use our remy function across any element we choose.

h1 { font-size: remy(32);}

div { width: remy(800);}

How to create a function

To start, you create a Sass function by using the @function directive. This is followed by the name of the function and any arguments enclosed in parentheses.

$col-count: 12;

@function col-pct($columns) {
    @return unquote((100/$col-count)*$columns+"%");
}

Remember a function only returns a value so we have to call @return to set the value returned by the function. Also note that the function can use any globally defined variables. The col-pct function above calculates the size in percentages of the specified number of columns. I am also using a built in Sass function, unquote to strip the quotes from the return value. Sass comes with a load of built in functions you can take a look at here.

How to use a function

A function is called by supplying the function name and any arguments. For example, to use the col-pct function to calculate the size of six columns:

.col-6 { width: col-pct(6);}

The resulting code is:

.col-6 { width: 50%; }

Arguments

We already saw that the function can use global variables. We can also use the same type of arguments we use with mixins. Of course we have to provide the arguments in the correct order. Lets say we modified the remy mixin to accept an argument for the rembase size.

@function remy($pxsize,$rembase) {
    @return ($pxsize/$rembase)+rem;
}

If we supply the arguments in the wrong order we will get an incorrect value. Unless of course we use keyword arguments

Keywords

We can call the new remy function with the arguments in any order if we use keywords.

h3 { font-size: remy2($rembase:8,$pxsize:32 );

This will work correctly since we used keyword arguments.

Default Values

We can also use default values with our functions. A way to improve the rem function further would be to include a default value. That way specifying the rem base value will be optional.

@function remy($pxsize,$rembase:16) {
    @return ($pxsize/$rembase)+rem;
}

We can then call the function one of two ways.

h3 { font-size: remy(32);}
p { font-size: remy(16,8);}

Both of these examples will work, although the rem base they are working from will be different.

Variable arguments

We can also use variable arguments in a function. The padding mixin from my @mixin article can be written as a function.

@function pad($pads...) {
@return $pads;
}

To use the function:

.five {padding: pad(25px,35px);}

.six {padding: pad(25px,35px,45px);}

.seven {padding: pad(25px,35px,45px,55px);}

Although functions are limited in their ability, I am sure you will be able to find some way to incorporate them into your projects. Try to strip out any logic for use across your projects in functions. If you come up with something useful it could come in handy in future projects.

Comments
HugoGiraudel

Please, for the love of God, do not append the unit as a string. This is an extremely bad practice I am trying to eradicate once and for all.

Adding a string to a number in order to give it a unit usually shows a very poor understanding of basic arithmetic. A unit is not just a random string at the end of a number. There are reasons why 5 metres per 5 metres gives you 25 square metres in real life. Sass units do not behave any differently.

To add a unit to a unitless number, either you should add 0 of this unit to the initial number, or multiply it by 1 of this unit. For instance, 42 * 1px or 42 + 0px are two perfectly valid ways to transform 42 into 42px. On the other hand 42 + px is a terrible way of casting the number in a length, because you end up with a string and not an actual number (as long as we stick to Sass data types).

It works exactly the same when you want to make a length (or what else) unitless: you don't slice the value to keep the numerical part. You divide it by 1 of this unit, for instance 42px / 1px. Same story.

More information about this:

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in Front-end, once a week, for free.