Sass in the Real World: book 1 of 4

Setting global default argument variables

Setting default argument values within the mixin is a good idea, but in our example the arguments themselves are non-variable values, and any changes to them down the road would require searching through our Sass to update the argument values. Suddenly we feel like we are back to the old days of CSS again.

A preferred method of managing argument default values is to set a global default variable. Leveraging Sass' !default flag will allow you to set a default value to a variable associated to an argument within a mixin that can be over-ridden at a global level.

Let's refactor our previous example, except this time I will replace all the hard coded default argument values with more flexible variable names. It is important to note that setting default values to an argument always require a key:value pair. Variables are scoped within a mixin, so setting a global variable of $padding will not work. While we could set a key:value pair like $padding: $padding this is considered a poor practice, especially with something named as generic as $padding.

In the following example, you will see how I set a simpler named argument to a mixin as this will be scoped, but we are assigning a global variable that is using a more specific naming convention to declare use.

$border-position-all: all !default;
$border-default-size: 1px !default;
$border-default-pattern: solid !default;
$border-default-color: $black !default;

@mixin add-border(
    $border-position: $border-position-all,
    $border-size: $border-default-size,
    $border-pattern: $border-default-pattern,
    $border-color: $border-default-color) {

  @if $border-position == $border-position-all {
    border: $border-size $border-pattern $border-color;
  }
  @else {
    border-#{$border-position}: $border-size
    $border-pattern $border-color;
  }
}

To set the default values to these newly created variables, typically in close relation to the mixin itself, we will set the values using the !default flag as illustrated in the following example.

Remember that global variables follow the rules of the cascade? Meaning, as a value is reset to a global variable within the document, each time that variable is referenced again thereafter, that new value will be used. This is not true for global variables that are using the !default flag.

In the following example we will see that by setting a global value to the variable $border-default-color higher up in the document, the !default value will be over-ridden, essentially breaking the pattern of the cascade.

// Global variable
$border-default-color: $dark-gray;

// !default values assigned mixin specified variables
$border-position-all: all !default;
$border-default-size: 1px !default;
$border-default-pattern: solid !default;
$border-default-color: $black !default;

// Mixin arguments set to specified variables as defaults
@mixin add-border(
    $border-position: $border-position-all,
    $border-size: $border-default-size,
    $border-pattern: $border-default-pattern,
    $border-color: $border-default-color) {

  @if $border-position == $border-position-all {
    border: $border-size $border-pattern $border-color;
  }
  @else {
    border-#{$border-position}: $border-size
    $border-pattern $border-color;
  }
}


// Selector using the mixin w/o passing in arguments
.block {
    width: 100%;
    padding: 5px;
    display: block;
    background-color: transparent;
    overflow: hidden;
    height: auto;
}

.block-border {
    @include add-border;
}

Notice in the output CSS how the $border-default-color is set to $dark-gray which in this example is equal to #444.

.block {
    width: 100%;
    padding: 5px;
    display: block;
    background-color: transparent;
    overflow: hidden;
    height: auto;
}

.block-border {
    border: 1px solid #444;
}

Following this pattern will allows you to use a more module style of creating mixins with default values that are easily over-ridden either by a global scope or local keyword value assignment.