Should I be using global or local Sass variables?

Computer displaying code

By

Sass provides many useful features. It gives web designers and developers the ability to DRY up our code with mixins, maps, and loops. It gives us a way to split up large files, but yet still cascade our stylesheets. And most importantly, it gives us variables.

Sass variables allow developers to build flexible, modular, and consistent stylesheets. However, at the same time, they can cause just as much harm as they do good.

“Thanks, Kurt. But I knew this already.” You’re probably thinking this right now. That’s fair. What I’m writing about is not a new concept. Variables for Sass have been around since the language’s initial release in 2006. But as CSS variables gain steam, it’s an important topic worth revisiting and discussing.

What Are Sass Variables

A variable, defined by a $ and proceeded by a name, contains a value to an argument. In Sass, they typically contain a CSS property value such as a hexadecimal color, unit of measurement, or Sass function. A few examples:

// Variable Examples
$black-base:   #2A2A2A;
$border:       1px solid;
$border-color: darken($black-base, 10%);

As you can see from these examples, the variables hold a defined value that can be used throughout your stylesheets. Let’s take a look at how we might use the above variables to style a selector. For the purpose of this blog post, I will write my examples in SCSS.

// Variables In Use Example
.button {
  background-color: $black-base;
  border: $border;
  border-color: $border-color;
}

The above example, however, does have a few problems. One of the most notable issues, they do not take into consideration the cascade of CSS. Meaning, we broadly defined our variable names. What happens if we need to define another $border variable? By using the same name we could override our first variable and cause unintended outcomes to our code. Let’s look at a few ways we can write variables to ensure we don’t have leaky code.

Better Naming Conventions

First, we can start by writing more descriptive variable names. In the example above we broadly defined our variable names. Take for instance $border this name doesn’t accurately describe the scope of this variable. Does it live in a component, module, page or global stylesheet?

Let’s say we scope these variables to a button component. We can then create more descriptive names for these variables by using the parent selector. It might looks something like this:

// Variables
$button-background-color:   #2A2A2A;
$button-border:             1px solid;
$button-border-color:       darken($black-base, 10%);

// Component
.button {
  background-color: $button-background-color;
  border: $button-border;
  border-color: $button-border-color;
}

As you can see, we have now scoped our variable names to the parent selector button. This helps us avoid leaky variables because we have become more descriptive with our naming conventions. Additionally, we would not use these variables outside of the button component file as they would not make sense from a naming convention standpoint.

Understanding Global vs Local Variables

Understanding the difference between local and global variables can help to contain unintended outcomes as well. They also help us to determine what we consider reusable and what is not.

First, let’s take a look at global variables.

What makes a global variable global? This type of variable is not scoped to a parent selector. Usually defined at the top of a stylesheet or in a stylesheet reserved for theme variables, these values are often reserved for colors, typography, borders, etc. While there are no hard or soft rules, we should think of them as theme-related variables. If the variable directly affects the outcome of a site’s or application’s core visual design then it should be considered global.

// Colors Variables
// ========================================

// Black
$black-base:    #2A2A2A;
$black-dark:    #000000;

// Blue
$blue-base:     #007BC1;

// Grey
$grey-light:    #E8E9EB;
$grey-base:     #86888B;

// Grey
$white-base:    #FFFFFF;

As you can see from the example above, the variables we created directly affect the outcome of the site’s color palette. These colors will need to be referenced throughout the site, thus we make them global variables. They do not have a parent selector and as long as they proceed with other selectors in the cascade, we can use them to add specific styles. They can also be used to assign values to local variables.

Now on to the second type of Sass variables, local variables. What makes a variable local versus global?

A local variable belongs to a selector. These variables are nested inside of the selector to prevent scope leak and because of this, can only be referenced by this selector and its nested children. Let’s take a look at an example.

// Button Component
.button {

  // Local Variables
  $button-background-color:   $black-base;
  $button-border:             1px solid;
  $button-border-color:       $black-dark;

  // Button Structure
  background-color: $button-background-color;
  border: $button-border;
  border-color: $button-border-color;
}

As you can see, the variables being referenced in the button structure section of our example utilize the locally scoped variables. Let’s take a look at one more example.

// Button Component
.button {
  // Local Variable
  $button-background-color:   $black-base;
  $button-border:             1px solid;
  $button-border-color:       $black-dark;
  $button-full-width:         100%;

  // Button Structure
  background-color: $button-background-color;
  border: $button-border;
  border-color: $button-border-color;

  &--full {
    width: $button-full-width;
  }
}

In this example, you can see we have defined a new local variable $button-full-width and we are passing it down to the new selector we created, $button--full. While the $button-full-width variable is not defined directly inside of the selector it styles, we can still call on this local variable because of the parent to child nested relationship between the button selector and button--full selector.

Additionally, you will notice in each of the last two examples we reference $black-base and $black-dark. These variables are not defined locally, but if you refer back to our global variables example, you will see we defined them as global variables. Once again, this means the variable is available for all selectors because it is not nested inside of a specific selector.

The mixture of both global and local variables in a small or large-scale web project helps to keep our code extendable and error-free. When kicking off a project or refactoring a previously developed project, keep these rules in mind.