UX Design and Development course

Setting Variables

When writing any CSS, look at some of the common values like the colors, fonts, font sizes, and the grid layout. These basic design elements need to be incorporated in your styelsheet. One of the ways Sass can greatly help is with variables. With Sass these common values can be abstracted and placed in associated variables which can be referenced when needed.

Variables allow you to name CSS values that you use repeatedly and then refer to them by name rather than repeating the value over and over. You can also name values you only use once in order to make it more clear what they’re for.

[^SassInAction]:excerpt from Sass and Compass in Action page 32

The major advantage of using variables in Sass is that now you have a single point of reference which allows for better maintainability and code extensibility. If there is any change to the CSS style, in theory changing the variable should handle the change (I mention in theory because sometimes practical issues provide exceptions to this rule). Let's look at the following variable declarations:

// Create primary color palette for the site

//Primary colors palette
// -------------------------
$blue:                  #3481CF !default;
$white:                 #FFFFFF !default;
$black:                 #000000 !default;
$gray:                  #7F7F7F !default;

// Create  derivative color palette from the primary color palette

//Derivative colors
// -------------------------
$dark-gray:             darken($gray, 23.14%) !default; //#444
$darker-gray:           darken($dark-gray, 6.6667%) !default; //#333
$darkest-gray:          darken($dark-gray, 17.25%) !default; //#181818

// Set a semantic alias to the color variable based on the dark gray color that was instantiated from the derivative colors

//Font information
//-----------------------
$font-color:    $darker-gray;
$anchor-color:  $darker-gray;

// Additionally, primary, secondary, tertiary, and any number of colors can be created

//Color use palette
//-----------------------
$primary-color: $blue;
$secondary-color: $black;
$tertiary-color: $white;

// When creating the base CSS, I will assign the font color alias variable that was instantiated earlier

p {
    color: $font-color;
}

a {
    color: $anchor-color;
    &:hover {
        color: darken($anchor-color, 20%);
    }
}

As illustrated in this this example, we are able to instantiate variables using values which, in this case, are hexadecimal colors. We can also instantiate additional variables using existing variables, this is referred to as aliasing. The functions used for the $dark-gray variable are existing color functions provided by Sass. We will cover functions in more detail in chapter 6, however in the meantime lets surmise that this function will take the existing gray color and darken it by 23.14%.

It is important to keep in mind that we now have created a maintainable and easily scaleable color scheme for our site. We will be referencing this set of colors throughout our Sass stylesheets. In the future, if there is a requirement for the color scheme to be changed, the change can be done at the point of instantiation in the _config.scss file. For example, if the requirement is that the the grays should be a shade darker for example instead of #7f7f7f we want #7b7b7b, we can change the $gray variable which will trickle down to all referenced variables in the stylesheet.

We have now created a file that will contain the basic variables for our site. A maintainable and scalable file for the stylesheet and site design. We will discuss this in more detail in the Using a _config file.

When discussing variables in any programming language, it's important to understand how variables are scoped. Let's take a look at how Sass handles the scoping of variables.

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 other imported Sass file. For example:

$text-color: blue;

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

Keeping true to the Cascading part of CSS, 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

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.

Setting the !default flag allows for a more flexible inclusion of the mixin within any stylesheet. It also allows me to easily reset the $border-position-all variable. Let's take a closer look at what the !default flag means and how I can take advantage of it.

The !default flag

Placing !default at the end of a variable declaration will have the following effect:

  • If the variable already has an assignment, it will not be re-assigned
  • Variables with null value will be considered unassigned and will be assigned with !default

The !default flag is extremely useful when creating plug-in type code and with mixins. Let's look at this text-color example mixin:

// Variable for $text-color is set to Blue

$text-color: blue;

@mixin text-color {
// Variable is only set to Red if it has not been set beforehand
  $text-color: red !default;
  color: $text-color;
}

.error {
  // Include mixin with !default color set
  @include text-color;
}

.normal-text {
  @include text-color;
}

Notice the !default flag at the end of the text-color variable inside the mixin? This allows the global variable of blue to override the value of red. Therefore the Sass will compile to the following:

.error {
  color: blue;
}

.normal-text {
  color: blue;
}

If we remove the global $text-color variable, Sass will make use of the !default set variable inside the mixin.

.error {
  color: red;
}

.normal-text {
  color: red;
}

It is important to remember that if the $text-color variable inside the mixin DID NOT have the !default flag, this variable's value would ALWAYS override any previously set value due to the cascade.

As illustrated, a more practical use of the !default flag is within mixins along with implementing a modular Sass architecture. Let's move our mixin, add-border, to a module file which I will call _decoration-mixins.scss:

$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 make use of this new tool, we will use Sass' @import rule to import into the website's stylesheet. Once imported, in the _config.scss file we can override any of the values set in this mixin, if necessary:

$border-default-pattern: dotted;
$border-default-color: lighten($gray, 25%);

@import "border";

.block-border {
    @include add-border($border-size: 2px);
}

This Sass will compile to:

.block-radius {
    border: 2px dotted #bfbfbf;
}

As you can see from these examples, a variable with the !default flag will only be set if the said variable has not been instantiated beforehand (or it is null). This is a very useful feature for modular (or OOCSS) design of our CSS. It is best practice to place the majority of the variables in a file for better maintenance and accessibility. The exception to this practice is when the variable is used only within a modular segment of the architecture.

In the above mixin, the variable $border-position-all: all !default; is instantiated in the mixin file. All other variables can be instantiated in a single file as in the _config.scss used in our sample project.

{#UsingAConfig}

Using a _config file

Let's take a look at our project and see how I will set our variables. Notice a file named config.scss. As stated in chapter 1, all of our Sass partials (Sass files that cannot stand on their own) will be preceded by an underscore, example.scss. For the project, I will be setting the following variables:

//URL variable
//-----------------------------
$base-img-url: '/images' !default;

// Primary colors
// -------------------------
$blue:                  #3481CF !default;
$white:                 #FFFFFF !default;
$black:                 #000000 !default;
$gray:                  #7F7F7F !default;

// Derivative colors
// -------------------------
$dark-gray:             darken($gray, 23.14%) !default; //#444
$darker-gray:           darken($dark-gray, 6.6667%) !default; //#333
$darkest-gray:          darken($dark-gray, 17.25%) !default; //#181818

//Color palette
//-----------------------
$primary-color: $blue;
$secondary-color: $black;
$tertiary-color: $white;

//Font information
//-----------------------
$header-font-family: "Georgia", "Times New Roman", serif !default;
$default-font-family: "HelveticaNeue", "Helvetica Neue", Helvetica,
Arial, sans-serif !default;
$default-browser-size: 16 !default;
$default-font-size: 14px !default;
$font-color:    $darker-gray;
$anchor-color: $darker-gray;

//Z-index variable
//-----------------------------
$starting-zindex: 1000 !default;
$zindex-modal-backdrop: $starting-zindex * 3 !default;
$zindex-modal: $zindex-modal-backdrop + 1 !default;

//Responsive
//-----------------------------
$small-screen-min-width: 320px !default;
$small-screen-max-width: 568px !default;
$medium-screen-min-width: 768px !default;
$medium-screen-max-width: 1024px !default;
$large-screen-min-width: 1824px !default;

This is a collection of variables that is made available to the stylesheet. This file will most likely be the first file imported into our project manifest to set the preliminary variables used throughout our stylesheet and mixins.