Sass in the Real World: book 1 of 4

Variable Scoping

In any programming language, scoping should be considered when setting variables. In Sass, all variables declared outside of a mixin or function will have a global scope and can be referenced in any Sass selector that uses the variable.

$text-color: blue;

html {
  font-family: Arial, sans-serfi;
  font-size: 1em;
  color: $text-color;
}

Keeping true to the Cascading part of CSS, currently if the value of the variable is changed, all further reference to the variable will be updated to the new value. This sounds logical but consider the following example:

// I instantiated the $text-color variable to Blue
$text-color: blue;

// Here, the intent was to change the color for the .error style
.error {
  $text-color: red;
  color: $text-color;
}

// Following the cascade, in .normal-text, I want Blue, but get Red.
.normal-text {
  color: $text-color;
}

The above Sass will compile to the following CSS:

.error {
  color: red;
}

.normal-text {
  color: red;
}

As you can see, the variable $text-color has a global scope and it is set to blue. However when I changed the $text-color variable to red, you will see that all further instances of $text-color variable will be red. This is common pitfall among novice Sass users. The best way to prevent this pitfall is to follow these guidelines:

  • Always set global variables and do not reset them throughout the stylesheet
  • Make use of !default flag

Arguments within Mixins and Functions

When setting variables in mixins or functions, keep the above scoping scenario in mind. If there is a variable that needs to be scoped within a mixin or function, declare it within the required scope. Consider the following:

@mixin add-border($border-position: all, $border-size: 1px,
  $border-pattern: solid, $border-color: black) {

  $border-position-all: all;

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

block {
  @include add-border();
}

In this example, we set a local variable border-position-all: all. We could also write the mixin as such:

$border-position-all: all !default;

@mixin add-border(
  $border-position: $border-position-all, $border-size: 1px,
  $border-pattern: solid, $border-color: black) {

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

Setting the border-position-all as a global variable, it can now be referenced throughout the application. The other difference here is that the $border-position-all variable uses the !default flag.

As you can looking at our $border-postion variable declaration, we have used a flag called !default. There are two flags that can be set when declaring a variable:

  • !default
  • !global

In the next section, we will take a closer look at how these flags work and how we can take advantage of them.